commit 850354781d84084307471e9a3f93fc16589c2e84 Author: ghost Date: Fri Sep 26 16:05:29 2025 +0200 Initial commit: current niom-turn state diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..77860e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Generated by Cargo +# will have compiled files and executables +debug +target +.DS_Store + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Generated by cargo mutants +# Contains mutation testing data +**/mutants.out*/ + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4ab571e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1079 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "niom-turn" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "crc32fast", + "hex", + "hmac", + "md5", + "rcgen", + "rustls 0.21.12", + "serde", + "serde_json", + "sha1", + "thiserror", + "tokio", + "tokio-rustls", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rcgen" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +dependencies = [ + "pem", + "ring 0.16.20", + "time", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring 0.16.20", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.14", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.14", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.14", + "untrusted 0.9.0", +] + +[[package]] +name = "serde" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring 0.17.14", + "untrusted 0.9.0", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f02f8ef --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "niom-turn" +version = "0.1.0" +edition = "2021" + +[dependencies] +# async runtime and networking +tokio = { version = "1.39", features = ["full"] } +bytes = "1.4" + +# crypto +hmac = "0.12" +sha1 = "0.10" +hex = "0.4" + +# config and logging +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["fmt"] } + +# TLS for turns (server) +tokio-rustls = "0.23" +rustls = "0.21" +rcgen = "0.9" + +# small STUN helper +uuid = { version = "1", features = ["v4"] } + +anyhow = "1.0" +async-trait = "0.1" +thiserror = "1.0" +crc32fast = "1.3" +md5 = "0.7" + diff --git a/README.md b/README.md new file mode 100644 index 0000000..2250698 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +niom-turn +========= + +Minimal TURN server scaffold for the niom project (MVP). + +Goals +- Provide a TURN server with long-term authentication and TLS (turns) for WebRTC clients. +- Start with a minimal, well-tested parsing/utility layer and an in-memory credential store interface that can be replaced later. + +Current status +- UDP listener on 0.0.0.0:3478 (STUN/TURN) implemented. +- STUN message parser + builder in `src/stun.rs`. +- CredentialStore trait + in-memory implementation in `src/auth.rs`. +- Minimal logic: on any STUN request, server replies with a 401 challenge (REALM + NONCE). + +Design +- Modules + - `stun.rs` - STUN/TURN message parsing and builders. + - `auth.rs` - CredentialStore trait and an `InMemoryStore` impl. Use the trait to swap for DB-backed stores later. + - `main.rs` - Bootstraps UDP listener, parses requests, and emits challenges for auth. + +CredentialStore interface +- `CredentialStore` is an async trait with `get_password(username) -> Option`. +- The default `InMemoryStore` is provided for tests and local dev. Swap in a production store by implementing the trait. + +How to build + +```bash +cd niom-turn +cargo build +``` + +How to test (quick local smoke) +- Start the server in one terminal (it listens on UDP/3478): + +```bash +cd niom-turn +cargo run +``` + +- From another machine or container, use a STUN client or `sipsak`/custom script to send a minimal STUN Binding request and observe the 401 reply. + +Next steps +- Implement full STUN attribute parsing (MESSAGE-INTEGRITY, FINGERPRINT). +- Implement long-term auth validation using MESSAGE-INTEGRITY. +- Implement Allocate + relayed sockets and permission handling. +- Add TLS listener (port 5349) using `tokio-rustls` and support `turns:`. + +Security / Deployment +- For production, run behind properly provisioned TLS certs (Let's Encrypt or mounted certs) and secure credential storage. +- Ensure UDP and TCP/TLS ports (3478/5349) are reachable from the internet when used as a public TURN server. + +Auth caveat +- The current in-repo long-term auth implementation is intentionally minimal for the MVP and + uses legacy constructs (A1/MD5 derivation + HMAC-SHA1 MESSAGE-INTEGRITY). MD5 is not recommended + for new secure systems — this is present for RFC compatibility and testing only. We will replace + this with a secure credential workflow (ephemeral/REST credentials, PBKDF/KDF storage, or mTLS) + before any production deployment. See `src/auth.rs` for the current simple store and helpers. + +License: MIT + +Smoke-Test (End-to-End) +----------------------- +Diese Anleitung beschreibt, wie du lokal den laufenden TURN/STUN-Server prüfst und welche Ergebnisse zu erwarten sind. + +1) Server starten + +Starte den Server im Projektverzeichnis; die Ausgabe wird normal in stdout geschrieben. In meinen Tests habe ich den Server im Hintergrund gestartet und die Logs in `/tmp/niom-turn-server.log` umgeleitet: + +```bash +cd niom-turn +# Im Vordergrund (für Entwicklung) +cargo run --bin niom-turn + +# Oder im Hintergrund mit Log-Redirect +cargo run --bin niom-turn &>/tmp/niom-turn-server.log & +``` + +2) Smoke-Client ausführen + +Das Repo enthält ein kleines Test-Binary `smoke_client`, das eine STUN Binding-Request mit `USERNAME` und `MESSAGE-INTEGRITY` an `127.0.0.1:3478` sendet. + +```bash +# Build (falls noch nicht gebaut) +cargo build --bin smoke_client + +# Ausführen +./target/debug/smoke_client +``` + +3) Erwartetes Ergebnis + +Der Smoke-Client gibt die erhaltenen Bytes aus. Bei einer erfolgreichen MESSAGE-INTEGRITY-Prüfung sendet der Server eine STUN Success Response (Message Type 0x0101). Beispielsweise habe ich folgende Rückgabe gesehen: + +``` +got 20 bytes from 127.0.0.1:3478 +[01, 01, 00, 00, 21, 12, a4, 42, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07] +``` + +Erklärung: +- `01 01` → STUN Success Response (0x0101) +- `21 12 a4 42` → Magic Cookie (0x2112A442) +- die folgenden 12 Bytes sind die Transaction ID (in diesem Test `07` wiederholt) + +Das bedeutet: Der Server hat die MESSAGE-INTEGRITY des Requests akzeptiert und eine 200-Antwort gesendet. + +Wenn stattdessen eine 401-Antwort (Challenge) ausgegeben wird, sieht man im Hex typischerweise einen Fehler-Response-Typ und REALM/NONCE-Attribute im Payload; das zeigt, dass die Authentifizierung nicht erfolgt ist und der Client die Challenge verarbeiten muss. + +Hinweis +- Die derzeitige Auth-Implementierung ist minimal und für Tests gedacht. Für Produktion bitte die README-Abschnitte "Auth caveat" beachten: sichere Credentials, TLS, und ggf. ephemeral credentials verwenden. + diff --git a/docs/plan-by-gpt5.odt b/docs/plan-by-gpt5.odt new file mode 100644 index 0000000..b7660cd Binary files /dev/null and b/docs/plan-by-gpt5.odt differ diff --git a/docs/rfc5389-stun.txt b/docs/rfc5389-stun.txt new file mode 100644 index 0000000..d2ea7e6 --- /dev/null +++ b/docs/rfc5389-stun.txt @@ -0,0 +1,2859 @@ + + + + + + +Network Working Group J. Rosenberg +Request for Comments: 5389 Cisco +Obsoletes: 3489 R. Mahy +Category: Standards Track P. Matthews + Unaffiliated + D. Wing + Cisco + October 2008 + + + Session Traversal Utilities for NAT (STUN) + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Abstract + + Session Traversal Utilities for NAT (STUN) is a protocol that serves + as a tool for other protocols in dealing with Network Address + Translator (NAT) traversal. It can be used by an endpoint to + determine the IP address and port allocated to it by a NAT. It can + also be used to check connectivity between two endpoints, and as a + keep-alive protocol to maintain NAT bindings. STUN works with many + existing NATs, and does not require any special behavior from them. + + STUN is not a NAT traversal solution by itself. Rather, it is a tool + to be used in the context of a NAT traversal solution. This is an + important change from the previous version of this specification (RFC + 3489), which presented STUN as a complete solution. + + This document obsoletes RFC 3489. + +Table of Contents + +1. Introduction ....................................................4 +2. Evolution from RFC 3489 .........................................4 +3. Overview of Operation ...........................................5 +4. Terminology .....................................................8 +5. Definitions .....................................................8 +6. STUN Message Structure .........................................10 +7. Base Protocol Procedures .......................................12 + 7.1. Forming a Request or an Indication ........................12 + 7.2. Sending the Request or Indication .........................13 + + + +Rosenberg, et al. Standards Track [Page 1] + +RFC 5389 STUN October 2008 + + + 7.2.1. Sending over UDP ...................................13 + 7.2.2. Sending over TCP or TLS-over-TCP ...................14 + 7.3. Receiving a STUN Message ..................................16 + 7.3.1. Processing a Request ...............................17 + 7.3.1.1. Forming a Success or Error Response .......18 + 7.3.1.2. Sending the Success or Error Response .....19 + 7.3.2. Processing an Indication ...........................19 + 7.3.3. Processing a Success Response ......................19 + 7.3.4. Processing an Error Response .......................20 +8. FINGERPRINT Mechanism ..........................................20 +9. DNS Discovery of a Server ......................................21 +10. Authentication and Message-Integrity Mechanisms ...............22 + 10.1. Short-Term Credential Mechanism ..........................22 + 10.1.1. Forming a Request or Indication ...................23 + 10.1.2. Receiving a Request or Indication .................23 + 10.1.3. Receiving a Response ..............................24 + 10.2. Long-Term Credential Mechanism ...........................24 + 10.2.1. Forming a Request .................................25 + 10.2.1.1. First Request ............................25 + 10.2.1.2. Subsequent Requests ......................26 + 10.2.2. Receiving a Request ...............................26 + 10.2.3. Receiving a Response ..............................27 +11. ALTERNATE-SERVER Mechanism ....................................28 +12. Backwards Compatibility with RFC 3489 .........................28 + 12.1. Changes to Client Processing .............................29 + 12.2. Changes to Server Processing .............................29 +13. Basic Server Behavior .........................................30 +14. STUN Usages ...................................................30 +15. STUN Attributes ...............................................31 + 15.1. MAPPED-ADDRESS ...........................................32 + 15.2. XOR-MAPPED-ADDRESS .......................................33 + 15.3. USERNAME .................................................34 + 15.4. MESSAGE-INTEGRITY ........................................34 + 15.5. FINGERPRINT ..............................................36 + 15.6. ERROR-CODE ...............................................36 + 15.7. REALM ....................................................38 + 15.8. NONCE ....................................................38 + 15.9. UNKNOWN-ATTRIBUTES .......................................38 + 15.10. SOFTWARE ................................................39 + 15.11. ALTERNATE-SERVER ........................................39 +16. Security Considerations .......................................39 + 16.1. Attacks against the Protocol .............................39 + 16.1.1. Outside Attacks ...................................39 + 16.1.2. Inside Attacks ....................................40 + 16.2. Attacks Affecting the Usage ..............................40 + 16.2.1. Attack I: Distributed DoS (DDoS) against a + Target ............................................41 + 16.2.2. Attack II: Silencing a Client .....................41 + + + +Rosenberg, et al. Standards Track [Page 2] + +RFC 5389 STUN October 2008 + + + 16.2.3. Attack III: Assuming the Identity of a Client .....42 + 16.2.4. Attack IV: Eavesdropping ..........................42 + 16.3. Hash Agility Plan ........................................42 +17. IAB Considerations ............................................42 +18. IANA Considerations ...........................................43 + 18.1. STUN Methods Registry ....................................43 + 18.2. STUN Attribute Registry ..................................43 + 18.3. STUN Error Code Registry .................................44 + 18.4. STUN UDP and TCP Port Numbers ............................45 +19. Changes since RFC 3489 ........................................45 +20. Contributors ..................................................47 +21. Acknowledgements ..............................................47 +22. References ....................................................47 + 22.1. Normative References .....................................47 + 22.2. Informative References ...................................48 +Appendix A. C Snippet to Determine STUN Message Types .............50 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 3] + +RFC 5389 STUN October 2008 + + +1. Introduction + + The protocol defined in this specification, Session Traversal + Utilities for NAT, provides a tool for dealing with NATs. It + provides a means for an endpoint to determine the IP address and port + allocated by a NAT that corresponds to its private IP address and + port. It also provides a way for an endpoint to keep a NAT binding + alive. With some extensions, the protocol can be used to do + connectivity checks between two endpoints [MMUSIC-ICE], or to relay + packets between two endpoints [BEHAVE-TURN]. + + In keeping with its tool nature, this specification defines an + extensible packet format, defines operation over several transport + protocols, and provides for two forms of authentication. + + STUN is intended to be used in context of one or more NAT traversal + solutions. These solutions are known as STUN usages. Each usage + describes how STUN is utilized to achieve the NAT traversal solution. + Typically, a usage indicates when STUN messages get sent, which + optional attributes to include, what server is used, and what + authentication mechanism is to be used. Interactive Connectivity + Establishment (ICE) [MMUSIC-ICE] is one usage of STUN. SIP Outbound + [SIP-OUTBOUND] is another usage of STUN. In some cases, a usage will + require extensions to STUN. A STUN extension can be in the form of + new methods, attributes, or error response codes. More information + on STUN usages can be found in Section 14. + +2. Evolution from RFC 3489 + + STUN was originally defined in RFC 3489 [RFC3489]. That + specification, sometimes referred to as "classic STUN", represented + itself as a complete solution to the NAT traversal problem. In that + solution, a client would discover whether it was behind a NAT, + determine its NAT type, discover its IP address and port on the + public side of the outermost NAT, and then utilize that IP address + and port within the body of protocols, such as the Session Initiation + Protocol (SIP) [RFC3261]. However, experience since the publication + of RFC 3489 has found that classic STUN simply does not work + sufficiently well to be a deployable solution. The address and port + learned through classic STUN are sometimes usable for communications + with a peer, and sometimes not. Classic STUN provided no way to + discover whether it would, in fact, work or not, and it provided no + remedy in cases where it did not. Furthermore, classic STUN's + algorithm for classification of NAT types was found to be faulty, as + many NATs did not fit cleanly into the types defined there. + + + + + + +Rosenberg, et al. Standards Track [Page 4] + +RFC 5389 STUN October 2008 + + + Classic STUN also had a security vulnerability -- attackers could + provide the client with incorrect mapped addresses under certain + topologies and constraints, and this was fundamentally not solvable + through any cryptographic means. Though this problem remains with + this specification, those attacks are now mitigated through the use + of more complete solutions that make use of STUN. + + For these reasons, this specification obsoletes RFC 3489, and instead + describes STUN as a tool that is utilized as part of a complete NAT + traversal solution. ICE [MMUSIC-ICE] is a complete NAT traversal + solution for protocols based on the offer/answer [RFC3264] + methodology, such as SIP. SIP Outbound [SIP-OUTBOUND] is a complete + solution for traversal of SIP signaling, and it uses STUN in a very + different way. Though it is possible that a protocol may be able to + use STUN by itself (classic STUN) as a traversal solution, such usage + is not described here and is strongly discouraged for the reasons + described above. + + The on-the-wire protocol described here is changed only slightly from + classic STUN. The protocol now runs over TCP in addition to UDP. + Extensibility was added to the protocol in a more structured way. A + magic cookie mechanism for demultiplexing STUN with application + protocols was added by stealing 32 bits from the 128-bit transaction + ID defined in RFC 3489, allowing the change to be backwards + compatible. Mapped addresses are encoded using a new exclusive-or + format. There are other, more minor changes. See Section 19 for a + more complete listing. + + Due to the change in scope, STUN has also been renamed from "Simple + Traversal of UDP through NAT" to "Session Traversal Utilities for + NAT". The acronym remains STUN, which is all anyone ever remembers + anyway. + +3. Overview of Operation + + This section is descriptive only. + + + + + + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 5] + +RFC 5389 STUN October 2008 + + + /-----\ + // STUN \\ + | Server | + \\ // + \-----/ + + + + + +--------------+ Public Internet + ................| NAT 2 |....................... + +--------------+ + + + + +--------------+ Private NET 2 + ................| NAT 1 |....................... + +--------------+ + + + + + /-----\ + // STUN \\ + | Client | + \\ // Private NET 1 + \-----/ + + + Figure 1: One Possible STUN Configuration + + One possible STUN configuration is shown in Figure 1. In this + configuration, there are two entities (called STUN agents) that + implement the STUN protocol. The lower agent in the figure is the + client, and is connected to private network 1. This network connects + to private network 2 through NAT 1. Private network 2 connects to + the public Internet through NAT 2. The upper agent in the figure is + the server, and resides on the public Internet. + + STUN is a client-server protocol. It supports two types of + transactions. One is a request/response transaction in which a + client sends a request to a server, and the server returns a + response. The second is an indication transaction in which either + agent -- client or server -- sends an indication that generates no + response. Both types of transactions include a transaction ID, which + is a randomly selected 96-bit number. For request/response + + + + + +Rosenberg, et al. Standards Track [Page 6] + +RFC 5389 STUN October 2008 + + + transactions, this transaction ID allows the client to associate the + response with the request that generated it; for indications, the + transaction ID serves as a debugging aid. + + All STUN messages start with a fixed header that includes a method, a + class, and the transaction ID. The method indicates which of the + various requests or indications this is; this specification defines + just one method, Binding, but other methods are expected to be + defined in other documents. The class indicates whether this is a + request, a success response, an error response, or an indication. + Following the fixed header comes zero or more attributes, which are + Type-Length-Value extensions that convey additional information for + the specific message. + + This document defines a single method called Binding. The Binding + method can be used either in request/response transactions or in + indication transactions. When used in request/response transactions, + the Binding method can be used to determine the particular "binding" + a NAT has allocated to a STUN client. When used in either request/ + response or in indication transactions, the Binding method can also + be used to keep these "bindings" alive. + + In the Binding request/response transaction, a Binding request is + sent from a STUN client to a STUN server. When the Binding request + arrives at the STUN server, it may have passed through one or more + NATs between the STUN client and the STUN server (in Figure 1, there + were two such NATs). As the Binding request message passes through a + NAT, the NAT will modify the source transport address (that is, the + source IP address and the source port) of the packet. As a result, + the source transport address of the request received by the server + will be the public IP address and port created by the NAT closest to + the server. This is called a reflexive transport address. The STUN + server copies that source transport address into an XOR-MAPPED- + ADDRESS attribute in the STUN Binding response and sends the Binding + response back to the STUN client. As this packet passes back through + a NAT, the NAT will modify the destination transport address in the + IP header, but the transport address in the XOR-MAPPED-ADDRESS + attribute within the body of the STUN response will remain untouched. + In this way, the client can learn its reflexive transport address + allocated by the outermost NAT with respect to the STUN server. + + In some usages, STUN must be multiplexed with other protocols (e.g., + [MMUSIC-ICE], [SIP-OUTBOUND]). In these usages, there must be a way + to inspect a packet and determine if it is a STUN packet or not. + STUN provides three fields in the STUN header with fixed values that + can be used for this purpose. If this is not sufficient, then STUN + packets can also contain a FINGERPRINT value, which can further be + used to distinguish the packets. + + + +Rosenberg, et al. Standards Track [Page 7] + +RFC 5389 STUN October 2008 + + + STUN defines a set of optional procedures that a usage can decide to + use, called mechanisms. These mechanisms include DNS discovery, a + redirection technique to an alternate server, a fingerprint attribute + for demultiplexing, and two authentication and message-integrity + exchanges. The authentication mechanisms revolve around the use of a + username, password, and message-integrity value. Two authentication + mechanisms, the long-term credential mechanism and the short-term + credential mechanism, are defined in this specification. Each usage + specifies the mechanisms allowed with that usage. + + In the long-term credential mechanism, the client and server share a + pre-provisioned username and password and perform a digest challenge/ + response exchange inspired by (but differing in details) to the one + defined for HTTP [RFC2617]. In the short-term credential mechanism, + the client and the server exchange a username and password through + some out-of-band method prior to the STUN exchange. For example, in + the ICE usage [MMUSIC-ICE] the two endpoints use out-of-band + signaling to exchange a username and password. These are used to + integrity protect and authenticate the request and response. There + is no challenge or nonce used. + +4. Terminology + + In this document, the key words "MUST", "MUST NOT", "REQUIRED", + "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", + and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119] and indicate requirement levels for compliant STUN + implementations. + +5. Definitions + + STUN Agent: A STUN agent is an entity that implements the STUN + protocol. The entity can be either a STUN client or a STUN + server. + + STUN Client: A STUN client is an entity that sends STUN requests and + receives STUN responses. A STUN client can also send indications. + In this specification, the terms STUN client and client are + synonymous. + + STUN Server: A STUN server is an entity that receives STUN requests + and sends STUN responses. A STUN server can also send + indications. In this specification, the terms STUN server and + server are synonymous. + + Transport Address: The combination of an IP address and port number + (such as a UDP or TCP port number). + + + + +Rosenberg, et al. Standards Track [Page 8] + +RFC 5389 STUN October 2008 + + + Reflexive Transport Address: A transport address learned by a client + that identifies that client as seen by another host on an IP + network, typically a STUN server. When there is an intervening + NAT between the client and the other host, the reflexive transport + address represents the mapped address allocated to the client on + the public side of the NAT. Reflexive transport addresses are + learned from the mapped address attribute (MAPPED-ADDRESS or XOR- + MAPPED-ADDRESS) in STUN responses. + + Mapped Address: Same meaning as reflexive address. This term is + retained only for historic reasons and due to the naming of the + MAPPED-ADDRESS and XOR-MAPPED-ADDRESS attributes. + + Long-Term Credential: A username and associated password that + represent a shared secret between client and server. Long-term + credentials are generally granted to the client when a subscriber + enrolls in a service and persist until the subscriber leaves the + service or explicitly changes the credential. + + Long-Term Password: The password from a long-term credential. + + Short-Term Credential: A temporary username and associated password + that represent a shared secret between client and server. Short- + term credentials are obtained through some kind of protocol + mechanism between the client and server, preceding the STUN + exchange. A short-term credential has an explicit temporal scope, + which may be based on a specific amount of time (such as 5 + minutes) or on an event (such as termination of a SIP dialog). + The specific scope of a short-term credential is defined by the + application usage. + + Short-Term Password: The password component of a short-term + credential. + + STUN Indication: A STUN message that does not receive a response. + + Attribute: The STUN term for a Type-Length-Value (TLV) object that + can be added to a STUN message. Attributes are divided into two + types: comprehension-required and comprehension-optional. STUN + agents can safely ignore comprehension-optional attributes they + don't understand, but cannot successfully process a message if it + contains comprehension-required attributes that are not + understood. + + RTO: Retransmission TimeOut, which defines the initial period of + time between transmission of a request and the first retransmit of + that request. + + + + +Rosenberg, et al. Standards Track [Page 9] + +RFC 5389 STUN October 2008 + + +6. STUN Message Structure + + STUN messages are encoded in binary using network-oriented format + (most significant byte or octet first, also commonly known as big- + endian). The transmission order is described in detail in Appendix B + of RFC 791 [RFC0791]. Unless otherwise noted, numeric constants are + in decimal (base 10). + + All STUN messages MUST start with a 20-byte header followed by zero + or more Attributes. The STUN header contains a STUN message type, + magic cookie, transaction ID, and message length. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0 0| STUN Message Type | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Magic Cookie | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | Transaction ID (96 bits) | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 2: Format of STUN Message Header + + The most significant 2 bits of every STUN message MUST be zeroes. + This can be used to differentiate STUN packets from other protocols + when STUN is multiplexed with other protocols on the same port. + + The message type defines the message class (request, success + response, failure response, or indication) and the message method + (the primary function) of the STUN message. Although there are four + message classes, there are only two types of transactions in STUN: + request/response transactions (which consist of a request message and + a response message) and indication transactions (which consist of a + single indication message). Response classes are split into error + and success responses to aid in quickly processing the STUN message. + + + + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 10] + +RFC 5389 STUN October 2008 + + + The message type field is decomposed further into the following + structure: + + 0 1 + 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + + +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ + |M |M |M|M|M|C|M|M|M|C|M|M|M|M| + |11|10|9|8|7|1|6|5|4|0|3|2|1|0| + +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 3: Format of STUN Message Type Field + + Here the bits in the message type field are shown as most significant + (M11) through least significant (M0). M11 through M0 represent a 12- + bit encoding of the method. C1 and C0 represent a 2-bit encoding of + the class. A class of 0b00 is a request, a class of 0b01 is an + indication, a class of 0b10 is a success response, and a class of + 0b11 is an error response. This specification defines a single + method, Binding. The method and class are orthogonal, so that for + each method, a request, success response, error response, and + indication are possible for that method. Extensions defining new + methods MUST indicate which classes are permitted for that method. + + For example, a Binding request has class=0b00 (request) and + method=0b000000000001 (Binding) and is encoded into the first 16 bits + as 0x0001. A Binding response has class=0b10 (success response) and + method=0b000000000001, and is encoded into the first 16 bits as + 0x0101. + + Note: This unfortunate encoding is due to assignment of values in + [RFC3489] that did not consider encoding Indications, Success, and + Errors using bit fields. + + The magic cookie field MUST contain the fixed value 0x2112A442 in + network byte order. In RFC 3489 [RFC3489], this field was part of + the transaction ID; placing the magic cookie in this location allows + a server to detect if the client will understand certain attributes + that were added in this revised specification. In addition, it aids + in distinguishing STUN packets from packets of other protocols when + STUN is multiplexed with those other protocols on the same port. + + The transaction ID is a 96-bit identifier, used to uniquely identify + STUN transactions. For request/response transactions, the + transaction ID is chosen by the STUN client for the request and + echoed by the server in the response. For indications, it is chosen + by the agent sending the indication. It primarily serves to + correlate requests with responses, though it also plays a small role + + + +Rosenberg, et al. Standards Track [Page 11] + +RFC 5389 STUN October 2008 + + + in helping to prevent certain types of attacks. The server also uses + the transaction ID as a key to identify each transaction uniquely + across all clients. As such, the transaction ID MUST be uniformly + and randomly chosen from the interval 0 .. 2**96-1, and SHOULD be + cryptographically random. Resends of the same request reuse the same + transaction ID, but the client MUST choose a new transaction ID for + new transactions unless the new request is bit-wise identical to the + previous request and sent from the same transport address to the same + IP address. Success and error responses MUST carry the same + transaction ID as their corresponding request. When an agent is + acting as a STUN server and STUN client on the same port, the + transaction IDs in requests sent by the agent have no relationship to + the transaction IDs in requests received by the agent. + + The message length MUST contain the size, in bytes, of the message + not including the 20-byte STUN header. Since all STUN attributes are + padded to a multiple of 4 bytes, the last 2 bits of this field are + always zero. This provides another way to distinguish STUN packets + from packets of other protocols. + + Following the STUN fixed portion of the header are zero or more + attributes. Each attribute is TLV (Type-Length-Value) encoded. The + details of the encoding, and of the attributes themselves are given + in Section 15. + +7. Base Protocol Procedures + + This section defines the base procedures of the STUN protocol. It + describes how messages are formed, how they are sent, and how they + are processed when they are received. It also defines the detailed + processing of the Binding method. Other sections in this document + describe optional procedures that a usage may elect to use in certain + situations. Other documents may define other extensions to STUN, by + adding new methods, new attributes, or new error response codes. + +7.1. Forming a Request or an Indication + + When formulating a request or indication message, the agent MUST + follow the rules in Section 6 when creating the header. In addition, + the message class MUST be either "Request" or "Indication" (as + appropriate), and the method must be either Binding or some method + defined in another document. + + The agent then adds any attributes specified by the method or the + usage. For example, some usages may specify that the agent use an + authentication method (Section 10) or the FINGERPRINT attribute + (Section 8). + + + + +Rosenberg, et al. Standards Track [Page 12] + +RFC 5389 STUN October 2008 + + + If the agent is sending a request, it SHOULD add a SOFTWARE attribute + to the request. Agents MAY include a SOFTWARE attribute in + indications, depending on the method. Extensions to STUN should + discuss whether SOFTWARE is useful in new indications. + + For the Binding method with no authentication, no attributes are + required unless the usage specifies otherwise. + + All STUN messages sent over UDP SHOULD be less than the path MTU, if + known. If the path MTU is unknown, messages SHOULD be the smaller of + 576 bytes and the first-hop MTU for IPv4 [RFC1122] and 1280 bytes for + IPv6 [RFC2460]. This value corresponds to the overall size of the IP + packet. Consequently, for IPv4, the actual STUN message would need + to be less than 548 bytes (576 minus 20-byte IP header, minus 8-byte + UDP header, assuming no IP options are used). STUN provides no + ability to handle the case where the request is under the MTU but the + response would be larger than the MTU. It is not envisioned that + this limitation will be an issue for STUN. The MTU limitation is a + SHOULD, and not a MUST, to account for cases where STUN itself is + being used to probe for MTU characteristics [BEHAVE-NAT]. Outside of + this or similar applications, the MTU constraint MUST be followed. + +7.2. Sending the Request or Indication + + The agent then sends the request or indication. This document + specifies how to send STUN messages over UDP, TCP, or TLS-over-TCP; + other transport protocols may be added in the future. The STUN usage + must specify which transport protocol is used, and how the agent + determines the IP address and port of the recipient. Section 9 + describes a DNS-based method of determining the IP address and port + of a server that a usage may elect to use. STUN may be used with + anycast addresses, but only with UDP and in usages where + authentication is not used. + + At any time, a client MAY have multiple outstanding STUN requests + with the same STUN server (that is, multiple transactions in + progress, with different transaction IDs). Absent other limits to + the rate of new transactions (such as those specified by ICE for + connectivity checks or when STUN is run over TCP), a client SHOULD + space new transactions to a server by RTO and SHOULD limit itself to + ten outstanding transactions to the same server. + +7.2.1. Sending over UDP + + When running STUN over UDP, it is possible that the STUN message + might be dropped by the network. Reliability of STUN request/ + response transactions is accomplished through retransmissions of the + + + + +Rosenberg, et al. Standards Track [Page 13] + +RFC 5389 STUN October 2008 + + + request message by the client application itself. STUN indications + are not retransmitted; thus, indication transactions over UDP are not + reliable. + + A client SHOULD retransmit a STUN request message starting with an + interval of RTO ("Retransmission TimeOut"), doubling after each + retransmission. The RTO is an estimate of the round-trip time (RTT), + and is computed as described in RFC 2988 [RFC2988], with two + exceptions. First, the initial value for RTO SHOULD be configurable + (rather than the 3 s recommended in RFC 2988) and SHOULD be greater + than 500 ms. The exception cases for this "SHOULD" are when other + mechanisms are used to derive congestion thresholds (such as the ones + defined in ICE for fixed rate streams), or when STUN is used in non- + Internet environments with known network capacities. In fixed-line + access links, a value of 500 ms is RECOMMENDED. Second, the value of + RTO SHOULD NOT be rounded up to the nearest second. Rather, a 1 ms + accuracy SHOULD be maintained. As with TCP, the usage of Karn's + algorithm is RECOMMENDED [KARN87]. When applied to STUN, it means + that RTT estimates SHOULD NOT be computed from STUN transactions that + result in the retransmission of a request. + + The value for RTO SHOULD be cached by a client after the completion + of the transaction, and used as the starting value for RTO for the + next transaction to the same server (based on equality of IP + address). The value SHOULD be considered stale and discarded after + 10 minutes. + + Retransmissions continue until a response is received, or until a + total of Rc requests have been sent. Rc SHOULD be configurable and + SHOULD have a default of 7. If, after the last request, a duration + equal to Rm times the RTO has passed without a response (providing + ample time to get a response if only this final request actually + succeeds), the client SHOULD consider the transaction to have failed. + Rm SHOULD be configurable and SHOULD have a default of 16. A STUN + transaction over UDP is also considered failed if there has been a + hard ICMP error [RFC1122]. For example, assuming an RTO of 500 ms, + requests would be sent at times 0 ms, 500 ms, 1500 ms, 3500 ms, 7500 + ms, 15500 ms, and 31500 ms. If the client has not received a + response after 39500 ms, the client will consider the transaction to + have timed out. + +7.2.2. Sending over TCP or TLS-over-TCP + + For TCP and TLS-over-TCP, the client opens a TCP connection to the + server. + + + + + + +Rosenberg, et al. Standards Track [Page 14] + +RFC 5389 STUN October 2008 + + + In some usages of STUN, STUN is sent as the only protocol over the + TCP connection. In this case, it can be sent without the aid of any + additional framing or demultiplexing. In other usages, or with other + extensions, it may be multiplexed with other data over a TCP + connection. In that case, STUN MUST be run on top of some kind of + framing protocol, specified by the usage or extension, which allows + for the agent to extract complete STUN messages and complete + application layer messages. The STUN service running on the well- + known port or ports discovered through the DNS procedures in + Section 9 is for STUN alone, and not for STUN multiplexed with other + data. Consequently, no framing protocols are used in connections to + those servers. When additional framing is utilized, the usage will + specify how the client knows to apply it and what port to connect to. + For example, in the case of ICE connectivity checks, this information + is learned through out-of-band negotiation between client and server. + + When STUN is run by itself over TLS-over-TCP, the + TLS_RSA_WITH_AES_128_CBC_SHA ciphersuite MUST be implemented at a + minimum. Implementations MAY also support any other ciphersuite. + When it receives the TLS Certificate message, the client SHOULD + verify the certificate and inspect the site identified by the + certificate. If the certificate is invalid or revoked, or if it does + not identify the appropriate party, the client MUST NOT send the STUN + message or otherwise proceed with the STUN transaction. The client + MUST verify the identity of the server. To do that, it follows the + identification procedures defined in Section 3.1 of RFC 2818 + [RFC2818]. Those procedures assume the client is dereferencing a + URI. For purposes of usage with this specification, the client + treats the domain name or IP address used in Section 8.1 as the host + portion of the URI that has been dereferenced. Alternatively, a + client MAY be configured with a set of domains or IP addresses that + are trusted; if a certificate is received that identifies one of + those domains or IP addresses, the client considers the identity of + the server to be verified. + + When STUN is run multiplexed with other protocols over a TLS-over-TCP + connection, the mandatory ciphersuites and TLS handling procedures + operate as defined by those protocols. + + Reliability of STUN over TCP and TLS-over-TCP is handled by TCP + itself, and there are no retransmissions at the STUN protocol level. + However, for a request/response transaction, if the client has not + received a response by Ti seconds after it sent the SYN to establish + the connection, it considers the transaction to have timed out. Ti + SHOULD be configurable and SHOULD have a default of 39.5s. This + value has been chosen to equalize the TCP and UDP timeouts for the + default initial RTO. + + + + +Rosenberg, et al. Standards Track [Page 15] + +RFC 5389 STUN October 2008 + + + In addition, if the client is unable to establish the TCP connection, + or the TCP connection is reset or fails before a response is + received, any request/response transaction in progress is considered + to have failed. + + The client MAY send multiple transactions over a single TCP (or TLS- + over-TCP) connection, and it MAY send another request before + receiving a response to the previous. The client SHOULD keep the + connection open until it: + + o has no further STUN requests or indications to send over that + connection, and + + o has no plans to use any resources (such as a mapped address + (MAPPED-ADDRESS or XOR-MAPPED-ADDRESS) or relayed address + [BEHAVE-TURN]) that were learned though STUN requests sent over + that connection, and + + o if multiplexing other application protocols over that port, has + finished using that other application, and + + o if using that learned port with a remote peer, has established + communications with that remote peer, as is required by some TCP + NAT traversal techniques (e.g., [MMUSIC-ICE-TCP]). + + At the server end, the server SHOULD keep the connection open, and + let the client close it, unless the server has determined that the + connection has timed out (for example, due to the client + disconnecting from the network). Bindings learned by the client will + remain valid in intervening NATs only while the connection remains + open. Only the client knows how long it needs the binding. The + server SHOULD NOT close a connection if a request was received over + that connection for which a response was not sent. A server MUST NOT + ever open a connection back towards the client in order to send a + response. Servers SHOULD follow best practices regarding connection + management in cases of overload. + +7.3. Receiving a STUN Message + + This section specifies the processing of a STUN message. The + processing specified here is for STUN messages as defined in this + specification; additional rules for backwards compatibility are + defined in Section 12. Those additional procedures are optional, and + usages can elect to utilize them. First, a set of processing + operations is applied that is independent of the class. This is + followed by class-specific processing, described in the subsections + that follow. + + + + +Rosenberg, et al. Standards Track [Page 16] + +RFC 5389 STUN October 2008 + + + When a STUN agent receives a STUN message, it first checks that the + message obeys the rules of Section 6. It checks that the first two + bits are 0, that the magic cookie field has the correct value, that + the message length is sensible, and that the method value is a + supported method. It checks that the message class is allowed for + the particular method. If the message class is "Success Response" or + "Error Response", the agent checks that the transaction ID matches a + transaction that is still in progress. If the FINGERPRINT extension + is being used, the agent checks that the FINGERPRINT attribute is + present and contains the correct value. If any errors are detected, + the message is silently discarded. In the case when STUN is being + multiplexed with another protocol, an error may indicate that this is + not really a STUN message; in this case, the agent should try to + parse the message as a different protocol. + + The STUN agent then does any checks that are required by a + authentication mechanism that the usage has specified (see + Section 10). + + Once the authentication checks are done, the STUN agent checks for + unknown attributes and known-but-unexpected attributes in the + message. Unknown comprehension-optional attributes MUST be ignored + by the agent. Known-but-unexpected attributes SHOULD be ignored by + the agent. Unknown comprehension-required attributes cause + processing that depends on the message class and is described below. + + At this point, further processing depends on the message class of the + request. + +7.3.1. Processing a Request + + If the request contains one or more unknown comprehension-required + attributes, the server replies with an error response with an error + code of 420 (Unknown Attribute), and includes an UNKNOWN-ATTRIBUTES + attribute in the response that lists the unknown comprehension- + required attributes. + + The server then does any additional checking that the method or the + specific usage requires. If all the checks succeed, the server + formulates a success response as described below. + + When run over UDP, a request received by the server could be the + first request of a transaction, or a retransmission. The server MUST + respond to retransmissions such that the following property is + preserved: if the client receives the response to the retransmission + and not the response that was sent to the original request, the + overall state on the client and server is identical to the case where + only the response to the original retransmission is received, or + + + +Rosenberg, et al. Standards Track [Page 17] + +RFC 5389 STUN October 2008 + + + where both responses are received (in which case the client will use + the first). The easiest way to meet this requirement is for the + server to remember all transaction IDs received over UDP and their + corresponding responses in the last 40 seconds. However, this + requires the server to hold state, and will be inappropriate for any + requests which are not authenticated. Another way is to reprocess + the request and recompute the response. The latter technique MUST + only be applied to requests that are idempotent (a request is + considered idempotent when the same request can be safely repeated + without impacting the overall state of the system) and result in the + same success response for the same request. The Binding method is + considered to be idempotent. Note that there are certain rare + network events that could cause the reflexive transport address value + to change, resulting in a different mapped address in different + success responses. Extensions to STUN MUST discuss the implications + of request retransmissions on servers that do not store transaction + state. + +7.3.1.1. Forming a Success or Error Response + + When forming the response (success or error), the server follows the + rules of Section 6. The method of the response is the same as that + of the request, and the message class is either "Success Response" or + "Error Response". + + For an error response, the server MUST add an ERROR-CODE attribute + containing the error code specified in the processing above. The + reason phrase is not fixed, but SHOULD be something suitable for the + error code. For certain errors, additional attributes are added to + the message. These attributes are spelled out in the description + where the error code is specified. For example, for an error code of + 420 (Unknown Attribute), the server MUST include an UNKNOWN- + ATTRIBUTES attribute. Certain authentication errors also cause + attributes to be added (see Section 10). Extensions may define other + errors and/or additional attributes to add in error cases. + + If the server authenticated the request using an authentication + mechanism, then the server SHOULD add the appropriate authentication + attributes to the response (see Section 10). + + The server also adds any attributes required by the specific method + or usage. In addition, the server SHOULD add a SOFTWARE attribute to + the message. + + For the Binding method, no additional checking is required unless the + usage specifies otherwise. When forming the success response, the + server adds a XOR-MAPPED-ADDRESS attribute to the response, where the + contents of the attribute are the source transport address of the + + + +Rosenberg, et al. Standards Track [Page 18] + +RFC 5389 STUN October 2008 + + + request message. For UDP, this is the source IP address and source + UDP port of the request message. For TCP and TLS-over-TCP, this is + the source IP address and source TCP port of the TCP connection as + seen by the server. + +7.3.1.2. Sending the Success or Error Response + + The response (success or error) is sent over the same transport as + the request was received on. If the request was received over UDP, + the destination IP address and port of the response are the source IP + address and port of the received request message, and the source IP + address and port of the response are equal to the destination IP + address and port of the received request message. If the request was + received over TCP or TLS-over-TCP, the response is sent back on the + same TCP connection as the request was received on. + +7.3.2. Processing an Indication + + If the indication contains unknown comprehension-required attributes, + the indication is discarded and processing ceases. + + The agent then does any additional checking that the method or the + specific usage requires. If all the checks succeed, the agent then + processes the indication. No response is generated for an + indication. + + For the Binding method, no additional checking or processing is + required, unless the usage specifies otherwise. The mere receipt of + the message by the agent has refreshed the "bindings" in the + intervening NATs. + + Since indications are not re-transmitted over UDP (unlike requests), + there is no need to handle re-transmissions of indications at the + sending agent. + +7.3.3. Processing a Success Response + + If the success response contains unknown comprehension-required + attributes, the response is discarded and the transaction is + considered to have failed. + + The client then does any additional checking that the method or the + specific usage requires. If all the checks succeed, the client then + processes the success response. + + For the Binding method, the client checks that the XOR-MAPPED-ADDRESS + attribute is present in the response. The client checks the address + family specified. If it is an unsupported address family, the + + + +Rosenberg, et al. Standards Track [Page 19] + +RFC 5389 STUN October 2008 + + + attribute SHOULD be ignored. If it is an unexpected but supported + address family (for example, the Binding transaction was sent over + IPv4, but the address family specified is IPv6), then the client MAY + accept and use the value. + +7.3.4. Processing an Error Response + + If the error response contains unknown comprehension-required + attributes, or if the error response does not contain an ERROR-CODE + attribute, then the transaction is simply considered to have failed. + + The client then does any processing specified by the authentication + mechanism (see Section 10). This may result in a new transaction + attempt. + + The processing at this point depends on the error code, the method, + and the usage; the following are the default rules: + + o If the error code is 300 through 399, the client SHOULD consider + the transaction as failed unless the ALTERNATE-SERVER extension is + being used. See Section 11. + + o If the error code is 400 through 499, the client declares the + transaction failed; in the case of 420 (Unknown Attribute), the + response should contain a UNKNOWN-ATTRIBUTES attribute that gives + additional information. + + o If the error code is 500 through 599, the client MAY resend the + request; clients that do so MUST limit the number of times they do + this. + + Any other error code causes the client to consider the transaction + failed. + +8. FINGERPRINT Mechanism + + This section describes an optional mechanism for STUN that aids in + distinguishing STUN messages from packets of other protocols when the + two are multiplexed on the same transport address. This mechanism is + optional, and a STUN usage must describe if and when it is used. The + FINGERPRINT mechanism is not backwards compatible with RFC 3489, and + cannot be used in environments where such compatibility is required. + + In some usages, STUN messages are multiplexed on the same transport + address as other protocols, such as the Real Time Transport Protocol + (RTP). In order to apply the processing described in Section 7, STUN + messages must first be separated from the application packets. + + + + +Rosenberg, et al. Standards Track [Page 20] + +RFC 5389 STUN October 2008 + + + Section 6 describes three fixed fields in the STUN header that can be + used for this purpose. However, in some cases, these three fixed + fields may not be sufficient. + + When the FINGERPRINT extension is used, an agent includes the + FINGERPRINT attribute in messages it sends to another agent. + Section 15.5 describes the placement and value of this attribute. + When the agent receives what it believes is a STUN message, then, in + addition to other basic checks, the agent also checks that the + message contains a FINGERPRINT attribute and that the attribute + contains the correct value. Section 7.3 describes when in the + overall processing of a STUN message the FINGERPRINT check is + performed. This additional check helps the agent detect messages of + other protocols that might otherwise seem to be STUN messages. + +9. DNS Discovery of a Server + + This section describes an optional procedure for STUN that allows a + client to use DNS to determine the IP address and port of a server. + A STUN usage must describe if and when this extension is used. To + use this procedure, the client must know a server's domain name and a + service name; the usage must also describe how the client obtains + these. Hard-coding the domain name of the server into software is + NOT RECOMMENDED in case the domain name is lost or needs to change + for legal or other reasons. + + When a client wishes to locate a STUN server in the public Internet + that accepts Binding request/response transactions, the SRV service + name is "stun". When it wishes to locate a STUN server that accepts + Binding request/response transactions over a TLS session, the SRV + service name is "stuns". STUN usages MAY define additional DNS SRV + service names. + + The domain name is resolved to a transport address using the SRV + procedures specified in [RFC2782]. The DNS SRV service name is the + service name provided as input to this procedure. The protocol in + the SRV lookup is the transport protocol the client will run STUN + over: "udp" for UDP and "tcp" for TCP. Note that only "tcp" is + defined with "stuns" at this time. + + The procedures of RFC 2782 are followed to determine the server to + contact. RFC 2782 spells out the details of how a set of SRV records + is sorted and then tried. However, RFC 2782 only states that the + client should "try to connect to the (protocol, address, service)" + without giving any details on what happens in the event of failure. + When following these procedures, if the STUN transaction times out + without receipt of a response, the client SHOULD retry the request to + + + + +Rosenberg, et al. Standards Track [Page 21] + +RFC 5389 STUN October 2008 + + + the next server in the ordered defined by RFC 2782. Such a retry is + only possible for request/response transmissions, since indication + transactions generate no response or timeout. + + The default port for STUN requests is 3478, for both TCP and UDP. + + Administrators of STUN servers SHOULD use this port in their SRV + records for UDP and TCP. In all cases, the port in DNS MUST reflect + the one on which the server is listening. The default port for STUN + over TLS is 5349. Servers can run STUN over TLS on the same port as + STUN over TCP if the server software supports determining whether the + initial message is a TLS or STUN message. + + If no SRV records were found, the client performs an A or AAAA record + lookup of the domain name. The result will be a list of IP + addresses, each of which can be contacted at the default port using + UDP or TCP, independent of the STUN usage. For usages that require + TLS, the client connects to one of the IP addresses using the default + STUN over TLS port. + +10. Authentication and Message-Integrity Mechanisms + + This section defines two mechanisms for STUN that a client and server + can use to provide authentication and message integrity; these two + mechanisms are known as the short-term credential mechanism and the + long-term credential mechanism. These two mechanisms are optional, + and each usage must specify if and when these mechanisms are used. + Consequently, both clients and servers will know which mechanism (if + any) to follow based on knowledge of which usage applies. For + example, a STUN server on the public Internet supporting ICE would + have no authentication, whereas the STUN server functionality in an + agent supporting connectivity checks would utilize short-term + credentials. An overview of these two mechanisms is given in + Section 3. + + Each mechanism specifies the additional processing required to use + that mechanism, extending the processing specified in Section 7. The + additional processing occurs in three different places: when forming + a message, when receiving a message immediately after the basic + checks have been performed, and when doing the detailed processing of + error responses. + +10.1. Short-Term Credential Mechanism + + The short-term credential mechanism assumes that, prior to the STUN + transaction, the client and server have used some other protocol to + exchange a credential in the form of a username and password. This + credential is time-limited. The time limit is defined by the usage. + + + +Rosenberg, et al. Standards Track [Page 22] + +RFC 5389 STUN October 2008 + + + As an example, in the ICE usage [MMUSIC-ICE], the two endpoints use + out-of-band signaling to agree on a username and password, and this + username and password are applicable for the duration of the media + session. + + This credential is used to form a message-integrity check in each + request and in many responses. There is no challenge and response as + in the long-term mechanism; consequently, replay is prevented by + virtue of the time-limited nature of the credential. + +10.1.1. Forming a Request or Indication + + For a request or indication message, the agent MUST include the + USERNAME and MESSAGE-INTEGRITY attributes in the message. The HMAC + for the MESSAGE-INTEGRITY attribute is computed as described in + Section 15.4. Note that the password is never included in the + request or indication. + +10.1.2. Receiving a Request or Indication + + After the agent has done the basic processing of a message, the agent + performs the checks listed below in order specified: + + o If the message does not contain both a MESSAGE-INTEGRITY and a + USERNAME attribute: + + * If the message is a request, the server MUST reject the request + with an error response. This response MUST use an error code + of 400 (Bad Request). + + * If the message is an indication, the agent MUST silently + discard the indication. + + o If the USERNAME does not contain a username value currently valid + within the server: + + * If the message is a request, the server MUST reject the request + with an error response. This response MUST use an error code + of 401 (Unauthorized). + + * If the message is an indication, the agent MUST silently + discard the indication. + + o Using the password associated with the username, compute the value + for the message integrity as described in Section 15.4. If the + resulting value does not match the contents of the MESSAGE- + INTEGRITY attribute: + + + + +Rosenberg, et al. Standards Track [Page 23] + +RFC 5389 STUN October 2008 + + + * If the message is a request, the server MUST reject the request + with an error response. This response MUST use an error code + of 401 (Unauthorized). + + * If the message is an indication, the agent MUST silently + discard the indication. + + If these checks pass, the agent continues to process the request or + indication. Any response generated by a server MUST include the + MESSAGE-INTEGRITY attribute, computed using the password utilized to + authenticate the request. The response MUST NOT contain the USERNAME + attribute. + + If any of the checks fail, a server MUST NOT include a MESSAGE- + INTEGRITY or USERNAME attribute in the error response. This is + because, in these failure cases, the server cannot determine the + shared secret necessary to compute MESSAGE-INTEGRITY. + +10.1.3. Receiving a Response + + The client looks for the MESSAGE-INTEGRITY attribute in the response. + If present, the client computes the message integrity over the + response as defined in Section 15.4, using the same password it + utilized for the request. If the resulting value matches the + contents of the MESSAGE-INTEGRITY attribute, the response is + considered authenticated. If the value does not match, or if + MESSAGE-INTEGRITY was absent, the response MUST be discarded, as if + it was never received. This means that retransmits, if applicable, + will continue. + +10.2. Long-Term Credential Mechanism + + The long-term credential mechanism relies on a long-term credential, + in the form of a username and password that are shared between client + and server. The credential is considered long-term since it is + assumed that it is provisioned for a user, and remains in effect + until the user is no longer a subscriber of the system, or is + changed. This is basically a traditional "log-in" username and + password given to users. + + Because these usernames and passwords are expected to be valid for + extended periods of time, replay prevention is provided in the form + of a digest challenge. In this mechanism, the client initially sends + a request, without offering any credentials or any integrity checks. + The server rejects this request, providing the user a realm (used to + guide the user or agent in selection of a username and password) and + a nonce. The nonce provides the replay protection. It is a cookie, + selected by the server, and encoded in such a way as to indicate a + + + +Rosenberg, et al. Standards Track [Page 24] + +RFC 5389 STUN October 2008 + + + duration of validity or client identity from which it is valid. The + client retries the request, this time including its username and the + realm, and echoing the nonce provided by the server. The client also + includes a message-integrity, which provides an HMAC over the entire + request, including the nonce. The server validates the nonce and + checks the message integrity. If they match, the request is + authenticated. If the nonce is no longer valid, it is considered + "stale", and the server rejects the request, providing a new nonce. + + In subsequent requests to the same server, the client reuses the + nonce, username, realm, and password it used previously. In this + way, subsequent requests are not rejected until the nonce becomes + invalid by the server, in which case the rejection provides a new + nonce to the client. + + Note that the long-term credential mechanism cannot be used to + protect indications, since indications cannot be challenged. Usages + utilizing indications must either use a short-term credential or omit + authentication and message integrity for them. + + Since the long-term credential mechanism is susceptible to offline + dictionary attacks, deployments SHOULD utilize passwords that are + difficult to guess. In cases where the credentials are not entered + by the user, but are rather placed on a client device during device + provisioning, the password SHOULD have at least 128 bits of + randomness. In cases where the credentials are entered by the user, + they should follow best current practices around password structure. + +10.2.1. Forming a Request + + There are two cases when forming a request. In the first case, this + is the first request from the client to the server (as identified by + its IP address and port). In the second case, the client is + submitting a subsequent request once a previous request/response + transaction has completed successfully. Forming a request as a + consequence of a 401 or 438 error response is covered in + Section 10.2.3 and is not considered a "subsequent request" and thus + does not utilize the rules described in Section 10.2.1.2. + +10.2.1.1. First Request + + If the client has not completed a successful request/response + transaction with the server (as identified by hostname, if the DNS + procedures of Section 9 are used, else IP address if not), it SHOULD + omit the USERNAME, MESSAGE-INTEGRITY, REALM, and NONCE attributes. + In other words, the very first request is sent as if there were no + authentication or message integrity applied. + + + + +Rosenberg, et al. Standards Track [Page 25] + +RFC 5389 STUN October 2008 + + +10.2.1.2. Subsequent Requests + + Once a request/response transaction has completed successfully, the + client will have been presented a realm and nonce by the server, and + selected a username and password with which it authenticated. The + client SHOULD cache the username, password, realm, and nonce for + subsequent communications with the server. When the client sends a + subsequent request, it SHOULD include the USERNAME, REALM, and NONCE + attributes with these cached values. It SHOULD include a MESSAGE- + INTEGRITY attribute, computed as described in Section 15.4 using the + cached password. + +10.2.2. Receiving a Request + + After the server has done the basic processing of a request, it + performs the checks listed below in the order specified: + + o If the message does not contain a MESSAGE-INTEGRITY attribute, the + server MUST generate an error response with an error code of 401 + (Unauthorized). This response MUST include a REALM value. It is + RECOMMENDED that the REALM value be the domain name of the + provider of the STUN server. The response MUST include a NONCE, + selected by the server. The response SHOULD NOT contain a + USERNAME or MESSAGE-INTEGRITY attribute. + + o If the message contains a MESSAGE-INTEGRITY attribute, but is + missing the USERNAME, REALM, or NONCE attribute, the server MUST + generate an error response with an error code of 400 (Bad + Request). This response SHOULD NOT include a USERNAME, NONCE, + REALM, or MESSAGE-INTEGRITY attribute. + + o If the NONCE is no longer valid, the server MUST generate an error + response with an error code of 438 (Stale Nonce). This response + MUST include NONCE and REALM attributes and SHOULD NOT include the + USERNAME or MESSAGE-INTEGRITY attribute. Servers can invalidate + nonces in order to provide additional security. See Section 4.3 + of [RFC2617] for guidelines. + + o If the username in the USERNAME attribute is not valid, the server + MUST generate an error response with an error code of 401 + (Unauthorized). This response MUST include a REALM value. It is + RECOMMENDED that the REALM value be the domain name of the + provider of the STUN server. The response MUST include a NONCE, + selected by the server. The response SHOULD NOT contain a + USERNAME or MESSAGE-INTEGRITY attribute. + + + + + + +Rosenberg, et al. Standards Track [Page 26] + +RFC 5389 STUN October 2008 + + + o Using the password associated with the username in the USERNAME + attribute, compute the value for the message integrity as + described in Section 15.4. If the resulting value does not match + the contents of the MESSAGE-INTEGRITY attribute, the server MUST + reject the request with an error response. This response MUST use + an error code of 401 (Unauthorized). It MUST include REALM and + NONCE attributes and SHOULD NOT include the USERNAME or MESSAGE- + INTEGRITY attribute. + + If these checks pass, the server continues to process the request. + Any response generated by the server (excepting the cases described + above) MUST include the MESSAGE-INTEGRITY attribute, computed using + the username and password utilized to authenticate the request. The + REALM, NONCE, and USERNAME attributes SHOULD NOT be included. + +10.2.3. Receiving a Response + + If the response is an error response with an error code of 401 + (Unauthorized), the client SHOULD retry the request with a new + transaction. This request MUST contain a USERNAME, determined by the + client as the appropriate username for the REALM from the error + response. The request MUST contain the REALM, copied from the error + response. The request MUST contain the NONCE, copied from the error + response. The request MUST contain the MESSAGE-INTEGRITY attribute, + computed using the password associated with the username in the + USERNAME attribute. The client MUST NOT perform this retry if it is + not changing the USERNAME or REALM or its associated password, from + the previous attempt. + + If the response is an error response with an error code of 438 (Stale + Nonce), the client MUST retry the request, using the new NONCE + supplied in the 438 (Stale Nonce) response. This retry MUST also + include the USERNAME, REALM, and MESSAGE-INTEGRITY. + + The client looks for the MESSAGE-INTEGRITY attribute in the response + (either success or failure). If present, the client computes the + message integrity over the response as defined in Section 15.4, using + the same password it utilized for the request. If the resulting + value matches the contents of the MESSAGE-INTEGRITY attribute, the + response is considered authenticated. If the value does not match, + or if MESSAGE-INTEGRITY was absent, the response MUST be discarded, + as if it was never received. This means that retransmits, if + applicable, will continue. + + + + + + + + +Rosenberg, et al. Standards Track [Page 27] + +RFC 5389 STUN October 2008 + + +11. ALTERNATE-SERVER Mechanism + + This section describes a mechanism in STUN that allows a server to + redirect a client to another server. This extension is optional, and + a usage must define if and when this extension is used. + + A server using this extension redirects a client to another server by + replying to a request message with an error response message with an + error code of 300 (Try Alternate). The server MUST include an + ALTERNATE-SERVER attribute in the error response. The error response + message MAY be authenticated; however, there are uses cases for + ALTERNATE-SERVER where authentication of the response is not possible + or practical. + + A client using this extension handles a 300 (Try Alternate) error + code as follows. The client looks for an ALTERNATE-SERVER attribute + in the error response. If one is found, then the client considers + the current transaction as failed, and reattempts the request with + the server specified in the attribute, using the same transport + protocol used for the previous request. That request, if + authenticated, MUST utilize the same credentials that the client + would have used in the request to the server that performed the + redirection. If the client has been redirected to a server on which + it has already tried this request within the last five minutes, it + MUST ignore the redirection and consider the transaction to have + failed. This prevents infinite ping-ponging between servers in case + of redirection loops. + +12. Backwards Compatibility with RFC 3489 + + This section defines procedures that allow a degree of backwards + compatibility with the original protocol defined in RFC 3489 + [RFC3489]. This mechanism is optional, meant to be utilized only in + cases where a new client can connect to an old server, or vice versa. + A usage must define if and when this procedure is used. + + Section 19 lists all the changes between this specification and RFC + 3489 [RFC3489]. However, not all of these differences are important, + because "classic STUN" was only used in a few specific ways. For the + purposes of this extension, the important changes are the following. + In RFC 3489: + + o UDP was the only supported transport. + + o The field that is now the magic cookie field was a part of the + transaction ID field, and transaction IDs were 128 bits long. + + + + + +Rosenberg, et al. Standards Track [Page 28] + +RFC 5389 STUN October 2008 + + + o The XOR-MAPPED-ADDRESS attribute did not exist, and the Binding + method used the MAPPED-ADDRESS attribute instead. + + o There were three comprehension-required attributes, RESPONSE- + ADDRESS, CHANGE-REQUEST, and CHANGED-ADDRESS, that have been + removed from this specification. + + * CHANGE-REQUEST and CHANGED-ADDRESS are now part of the NAT + Behavior Discovery usage [BEHAVE-NAT], and the other is + deprecated. + +12.1. Changes to Client Processing + + A client that wants to interoperate with an [RFC3489] server SHOULD + send a request message that uses the Binding method, contains no + attributes, and uses UDP as the transport protocol to the server. If + successful, the success response received from the server will + contain a MAPPED-ADDRESS attribute rather than an XOR-MAPPED-ADDRESS + attribute. A client seeking to interoperate with an older server + MUST be prepared to receive either. Furthermore, the client MUST + ignore any Reserved comprehension-required attributes that might + appear in the response. Of the Reserved attributes in Section 18.2, + 0x0002, 0x0004, 0x0005, and 0x000B may appear in Binding responses + from a server compliant to RFC 3489. Other than this change, the + processing of the response is identical to the procedures described + above. + +12.2. Changes to Server Processing + + A STUN server can detect when a given Binding request message was + sent from an RFC 3489 [RFC3489] client by the absence of the correct + value in the magic cookie field. When the server detects an RFC 3489 + client, it SHOULD copy the value seen in the magic cookie field in + the Binding request to the magic cookie field in the Binding response + message, and insert a MAPPED-ADDRESS attribute instead of an XOR- + MAPPED-ADDRESS attribute. + + The client might, in rare situations, include either the RESPONSE- + ADDRESS or CHANGE-REQUEST attributes. In these situations, the + server will view these as unknown comprehension-required attributes + and reply with an error response. Since the mechanisms utilizing + those attributes are no longer supported, this behavior is + acceptable. + + The RFC 3489 version of STUN lacks both the magic cookie and the + FINGERPRINT attribute that allows for a very high probability of + correctly identifying STUN messages when multiplexed with other + protocols. Therefore, STUN implementations that are backwards + + + +Rosenberg, et al. Standards Track [Page 29] + +RFC 5389 STUN October 2008 + + + compatible with RFC 3489 SHOULD NOT be used in cases where STUN will + be multiplexed with another protocol. However, that should not be an + issue as such multiplexing was not available in RFC 3489. + +13. Basic Server Behavior + + This section defines the behavior of a basic, stand-alone STUN + server. A basic STUN server provides clients with server reflexive + transport addresses by receiving and replying to STUN Binding + requests. + + The STUN server MUST support the Binding method. It SHOULD NOT + utilize the short-term or long-term credential mechanism. This is + because the work involved in authenticating the request is more than + the work in simply processing it. It SHOULD NOT utilize the + ALTERNATE-SERVER mechanism for the same reason. It MUST support UDP + and TCP. It MAY support STUN over TCP/TLS; however, TLS provides + minimal security benefits in this basic mode of operation. It MAY + utilize the FINGERPRINT mechanism but MUST NOT require it. Since the + stand-alone server only runs STUN, FINGERPRINT provides no benefit. + Requiring it would break compatibility with RFC 3489, and such + compatibility is desirable in a stand-alone server. Stand-alone STUN + servers SHOULD support backwards compatibility with [RFC3489] + clients, as described in Section 12. + + It is RECOMMENDED that administrators of STUN servers provide DNS + entries for those servers as described in Section 9. + + A basic STUN server is not a solution for NAT traversal by itself. + However, it can be utilized as part of a solution through STUN + usages. This is discussed further in Section 14. + +14. STUN Usages + + STUN by itself is not a solution to the NAT traversal problem. + Rather, STUN defines a tool that can be used inside a larger + solution. The term "STUN usage" is used for any solution that uses + STUN as a component. + + At the time of writing, three STUN usages are defined: Interactive + Connectivity Establishment (ICE) [MMUSIC-ICE], Client-initiated + connections for SIP [SIP-OUTBOUND], and NAT Behavior Discovery + [BEHAVE-NAT]. Other STUN usages may be defined in the future. + + A STUN usage defines how STUN is actually utilized -- when to send + requests, what to do with the responses, and which optional + procedures defined here (or in an extension to STUN) are to be used. + A usage would also define: + + + +Rosenberg, et al. Standards Track [Page 30] + +RFC 5389 STUN October 2008 + + + o Which STUN methods are used. + + o What authentication and message-integrity mechanisms are used. + + o The considerations around manual vs. automatic key derivation for + the integrity mechanism, as discussed in [RFC4107]. + + o What mechanisms are used to distinguish STUN messages from other + messages. When STUN is run over TCP, a framing mechanism may be + required. + + o How a STUN client determines the IP address and port of the STUN + server. + + o Whether backwards compatibility to RFC 3489 is required. + + o What optional attributes defined here (such as FINGERPRINT and + ALTERNATE-SERVER) or in other extensions are required. + + In addition, any STUN usage must consider the security implications + of using STUN in that usage. A number of attacks against STUN are + known (see the Security Considerations section in this document), and + any usage must consider how these attacks can be thwarted or + mitigated. + + Finally, a usage must consider whether its usage of STUN is an + example of the Unilateral Self-Address Fixing approach to NAT + traversal, and if so, address the questions raised in RFC 3424 + [RFC3424]. + +15. STUN Attributes + + After the STUN header are zero or more attributes. Each attribute + MUST be TLV encoded, with a 16-bit type, 16-bit length, and value. + Each STUN attribute MUST end on a 32-bit boundary. As mentioned + above, all fields in an attribute are transmitted most significant + bit first. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Value (variable) .... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 4: Format of STUN Attributes + + + + +Rosenberg, et al. Standards Track [Page 31] + +RFC 5389 STUN October 2008 + + + The value in the length field MUST contain the length of the Value + part of the attribute, prior to padding, measured in bytes. Since + STUN aligns attributes on 32-bit boundaries, attributes whose content + is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of + padding so that its value contains a multiple of 4 bytes. The + padding bits are ignored, and may be any value. + + Any attribute type MAY appear more than once in a STUN message. + Unless specified otherwise, the order of appearance is significant: + only the first occurrence needs to be processed by a receiver, and + any duplicates MAY be ignored by a receiver. + + To allow future revisions of this specification to add new attributes + if needed, the attribute space is divided into two ranges. + Attributes with type values between 0x0000 and 0x7FFF are + comprehension-required attributes, which means that the STUN agent + cannot successfully process the message unless it understands the + attribute. Attributes with type values between 0x8000 and 0xFFFF are + comprehension-optional attributes, which means that those attributes + can be ignored by the STUN agent if it does not understand them. + + The set of STUN attribute types is maintained by IANA. The initial + set defined by this specification is found in Section 18.2. + + The rest of this section describes the format of the various + attributes defined in this specification. + +15.1. MAPPED-ADDRESS + + The MAPPED-ADDRESS attribute indicates a reflexive transport address + of the client. It consists of an 8-bit address family and a 16-bit + port, followed by a fixed-length value representing the IP address. + If the address family is IPv4, the address MUST be 32 bits. If the + address family is IPv6, the address MUST be 128 bits. All fields + must be in network byte order. + + + + + + + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 32] + +RFC 5389 STUN October 2008 + + + The format of the MAPPED-ADDRESS attribute is: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0 0 0 0 0 0 0 0| Family | Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | Address (32 bits or 128 bits) | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 5: Format of MAPPED-ADDRESS Attribute + + The address family can take on the following values: + + 0x01:IPv4 + 0x02:IPv6 + + The first 8 bits of the MAPPED-ADDRESS MUST be set to 0 and MUST be + ignored by receivers. These bits are present for aligning parameters + on natural 32-bit boundaries. + + This attribute is used only by servers for achieving backwards + compatibility with RFC 3489 [RFC3489] clients. + +15.2. XOR-MAPPED-ADDRESS + + The XOR-MAPPED-ADDRESS attribute is identical to the MAPPED-ADDRESS + attribute, except that the reflexive transport address is obfuscated + through the XOR function. + + The format of the XOR-MAPPED-ADDRESS is: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |x x x x x x x x| Family | X-Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | X-Address (Variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 6: Format of XOR-MAPPED-ADDRESS Attribute + + The Family represents the IP address family, and is encoded + identically to the Family in MAPPED-ADDRESS. + + + + + +Rosenberg, et al. Standards Track [Page 33] + +RFC 5389 STUN October 2008 + + + X-Port is computed by taking the mapped port in host byte order, + XOR'ing it with the most significant 16 bits of the magic cookie, and + then the converting the result to network byte order. If the IP + address family is IPv4, X-Address is computed by taking the mapped IP + address in host byte order, XOR'ing it with the magic cookie, and + converting the result to network byte order. If the IP address + family is IPv6, X-Address is computed by taking the mapped IP address + in host byte order, XOR'ing it with the concatenation of the magic + cookie and the 96-bit transaction ID, and converting the result to + network byte order. + + The rules for encoding and processing the first 8 bits of the + attribute's value, the rules for handling multiple occurrences of the + attribute, and the rules for processing address families are the same + as for MAPPED-ADDRESS. + + Note: XOR-MAPPED-ADDRESS and MAPPED-ADDRESS differ only in their + encoding of the transport address. The former encodes the transport + address by exclusive-or'ing it with the magic cookie. The latter + encodes it directly in binary. RFC 3489 originally specified only + MAPPED-ADDRESS. However, deployment experience found that some NATs + rewrite the 32-bit binary payloads containing the NAT's public IP + address, such as STUN's MAPPED-ADDRESS attribute, in the well-meaning + but misguided attempt at providing a generic ALG function. Such + behavior interferes with the operation of STUN and also causes + failure of STUN's message-integrity checking. + +15.3. USERNAME + + The USERNAME attribute is used for message integrity. It identifies + the username and password combination used in the message-integrity + check. + + The value of USERNAME is a variable-length value. It MUST contain a + UTF-8 [RFC3629] encoded sequence of less than 513 bytes, and MUST + have been processed using SASLprep [RFC4013]. + +15.4. MESSAGE-INTEGRITY + + The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of + the STUN message. The MESSAGE-INTEGRITY attribute can be present in + any STUN message type. Since it uses the SHA1 hash, the HMAC will be + 20 bytes. The text used as input to HMAC is the STUN message, + including the header, up to and including the attribute preceding the + MESSAGE-INTEGRITY attribute. With the exception of the FINGERPRINT + attribute, which appears after MESSAGE-INTEGRITY, agents MUST ignore + all other attributes that follow MESSAGE-INTEGRITY. + + + + +Rosenberg, et al. Standards Track [Page 34] + +RFC 5389 STUN October 2008 + + + The key for the HMAC depends on whether long-term or short-term + credentials are in use. For long-term credentials, the key is 16 + bytes: + + key = MD5(username ":" realm ":" SASLprep(password)) + + That is, the 16-byte key is formed by taking the MD5 hash of the + result of concatenating the following five fields: (1) the username, + with any quotes and trailing nulls removed, as taken from the + USERNAME attribute (in which case SASLprep has already been applied); + (2) a single colon; (3) the realm, with any quotes and trailing nulls + removed; (4) a single colon; and (5) the password, with any trailing + nulls removed and after processing using SASLprep. For example, if + the username was 'user', the realm was 'realm', and the password was + 'pass', then the 16-byte HMAC key would be the result of performing + an MD5 hash on the string 'user:realm:pass', the resulting hash being + 0x8493fbc53ba582fb4c044c456bdc40eb. + + For short-term credentials: + + key = SASLprep(password) + + where MD5 is defined in RFC 1321 [RFC1321] and SASLprep() is defined + in RFC 4013 [RFC4013]. + + The structure of the key when used with long-term credentials + facilitates deployment in systems that also utilize SIP. Typically, + SIP systems utilizing SIP's digest authentication mechanism do not + actually store the password in the database. Rather, they store a + value called H(A1), which is equal to the key defined above. + + Based on the rules above, the hash used to construct MESSAGE- + INTEGRITY includes the length field from the STUN message header. + Prior to performing the hash, the MESSAGE-INTEGRITY attribute MUST be + inserted into the message (with dummy content). The length MUST then + be set to point to the length of the message up to, and including, + the MESSAGE-INTEGRITY attribute itself, but excluding any attributes + after it. Once the computation is performed, the value of the + MESSAGE-INTEGRITY attribute can be filled in, and the value of the + length in the STUN header can be set to its correct value -- the + length of the entire message. Similarly, when validating the + MESSAGE-INTEGRITY, the length field should be adjusted to point to + the end of the MESSAGE-INTEGRITY attribute prior to calculating the + HMAC. Such adjustment is necessary when attributes, such as + FINGERPRINT, appear after MESSAGE-INTEGRITY. + + + + + + +Rosenberg, et al. Standards Track [Page 35] + +RFC 5389 STUN October 2008 + + +15.5. FINGERPRINT + + The FINGERPRINT attribute MAY be present in all STUN messages. The + value of the attribute is computed as the CRC-32 of the STUN message + up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with + the 32-bit value 0x5354554e (the XOR helps in cases where an + application packet is also using CRC-32 in it). The 32-bit CRC is + the one defined in ITU V.42 [ITU.V42.2002], which has a generator + polynomial of x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1. + When present, the FINGERPRINT attribute MUST be the last attribute in + the message, and thus will appear after MESSAGE-INTEGRITY. + + The FINGERPRINT attribute can aid in distinguishing STUN packets from + packets of other protocols. See Section 8. + + As with MESSAGE-INTEGRITY, the CRC used in the FINGERPRINT attribute + covers the length field from the STUN message header. Therefore, + this value must be correct and include the CRC attribute as part of + the message length, prior to computation of the CRC. When using the + FINGERPRINT attribute in a message, the attribute is first placed + into the message with a dummy value, then the CRC is computed, and + then the value of the attribute is updated. If the MESSAGE-INTEGRITY + attribute is also present, then it must be present with the correct + message-integrity value before the CRC is computed, since the CRC is + done over the value of the MESSAGE-INTEGRITY attribute as well. + +15.6. ERROR-CODE + + The ERROR-CODE attribute is used in error response messages. It + contains a numeric error code value in the range of 300 to 699 plus a + textual reason phrase encoded in UTF-8 [RFC3629], and is consistent + in its code assignments and semantics with SIP [RFC3261] and HTTP + [RFC2616]. The reason phrase is meant for user consumption, and can + be anything appropriate for the error code. Recommended reason + phrases for the defined error codes are included in the IANA registry + for error codes. The reason phrase MUST be a UTF-8 [RFC3629] encoded + sequence of less than 128 characters (which can be as long as 763 + bytes). + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reserved, should be 0 |Class| Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reason Phrase (variable) .. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 7: ERROR-CODE Attribute + + + +Rosenberg, et al. Standards Track [Page 36] + +RFC 5389 STUN October 2008 + + + To facilitate processing, the class of the error code (the hundreds + digit) is encoded separately from the rest of the code, as shown in + Figure 7. + + The Reserved bits SHOULD be 0, and are for alignment on 32-bit + boundaries. Receivers MUST ignore these bits. The Class represents + the hundreds digit of the error code. The value MUST be between 3 + and 6. The Number represents the error code modulo 100, and its + value MUST be between 0 and 99. + + The following error codes, along with their recommended reason + phrases, are defined: + + 300 Try Alternate: The client should contact an alternate server for + this request. This error response MUST only be sent if the + request included a USERNAME attribute and a valid MESSAGE- + INTEGRITY attribute; otherwise, it MUST NOT be sent and error + code 400 (Bad Request) is suggested. This error response MUST + be protected with the MESSAGE-INTEGRITY attribute, and receivers + MUST validate the MESSAGE-INTEGRITY of this response before + redirecting themselves to an alternate server. + + Note: Failure to generate and validate message integrity + for a 300 response allows an on-path attacker to falsify a + 300 response thus causing subsequent STUN messages to be + sent to a victim. + + 400 Bad Request: The request was malformed. The client SHOULD NOT + retry the request without modification from the previous + attempt. The server may not be able to generate a valid + MESSAGE-INTEGRITY for this error, so the client MUST NOT expect + a valid MESSAGE-INTEGRITY attribute on this response. + + 401 Unauthorized: The request did not contain the correct + credentials to proceed. The client should retry the request + with proper credentials. + + 420 Unknown Attribute: The server received a STUN packet containing + a comprehension-required attribute that it did not understand. + The server MUST put this unknown attribute in the UNKNOWN- + ATTRIBUTE attribute of its error response. + + 438 Stale Nonce: The NONCE used by the client was no longer valid. + The client should retry, using the NONCE provided in the + response. + + 500 Server Error: The server has suffered a temporary error. The + client should try again. + + + +Rosenberg, et al. Standards Track [Page 37] + +RFC 5389 STUN October 2008 + + +15.7. REALM + + The REALM attribute may be present in requests and responses. It + contains text that meets the grammar for "realm-value" as described + in RFC 3261 [RFC3261] but without the double quotes and their + surrounding whitespace. That is, it is an unquoted realm-value (and + is therefore a sequence of qdtext or quoted-pair). It MUST be a + UTF-8 [RFC3629] encoded sequence of less than 128 characters (which + can be as long as 763 bytes), and MUST have been processed using + SASLprep [RFC4013]. + + Presence of the REALM attribute in a request indicates that long-term + credentials are being used for authentication. Presence in certain + error responses indicates that the server wishes the client to use a + long-term credential for authentication. + +15.8. NONCE + + The NONCE attribute may be present in requests and responses. It + contains a sequence of qdtext or quoted-pair, which are defined in + RFC 3261 [RFC3261]. Note that this means that the NONCE attribute + will not contain actual quote characters. See RFC 2617 [RFC2617], + Section 4.3, for guidance on selection of nonce values in a server. + + It MUST be less than 128 characters (which can be as long as 763 + bytes). + +15.9. UNKNOWN-ATTRIBUTES + + The UNKNOWN-ATTRIBUTES attribute is present only in an error response + when the response code in the ERROR-CODE attribute is 420. + + The attribute contains a list of 16-bit values, each of which + represents an attribute type that was not understood by the server. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attribute 1 Type | Attribute 2 Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attribute 3 Type | Attribute 4 Type ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Figure 8: Format of UNKNOWN-ATTRIBUTES Attribute + + + + + + +Rosenberg, et al. Standards Track [Page 38] + +RFC 5389 STUN October 2008 + + + Note: In [RFC3489], this field was padded to 32 by duplicating the + last attribute. In this version of the specification, the normal + padding rules for attributes are used instead. + +15.10. SOFTWARE + + The SOFTWARE attribute contains a textual description of the software + being used by the agent sending the message. It is used by clients + and servers. Its value SHOULD include manufacturer and version + number. The attribute has no impact on operation of the protocol, + and serves only as a tool for diagnostic and debugging purposes. The + value of SOFTWARE is variable length. It MUST be a UTF-8 [RFC3629] + encoded sequence of less than 128 characters (which can be as long as + 763 bytes). + +15.11. ALTERNATE-SERVER + + The alternate server represents an alternate transport address + identifying a different STUN server that the STUN client should try. + + It is encoded in the same way as MAPPED-ADDRESS, and thus refers to a + single server by IP address. The IP address family MUST be identical + to that of the source IP address of the request. + +16. Security Considerations + +16.1. Attacks against the Protocol + +16.1.1. Outside Attacks + + An attacker can try to modify STUN messages in transit, in order to + cause a failure in STUN operation. These attacks are detected for + both requests and responses through the message-integrity mechanism, + using either a short-term or long-term credential. Of course, once + detected, the manipulated packets will be dropped, causing the STUN + transaction to effectively fail. This attack is possible only by an + on-path attacker. + + An attacker that can observe, but not modify, STUN messages in- + transit (for example, an attacker present on a shared access medium, + such as Wi-Fi), can see a STUN request, and then immediately send a + STUN response, typically an error response, in order to disrupt STUN + processing. This attack is also prevented for messages that utilize + MESSAGE-INTEGRITY. However, some error responses, those related to + authentication in particular, cannot be protected by MESSAGE- + INTEGRITY. When STUN itself is run over a secure transport protocol + (e.g., TLS), these attacks are completely mitigated. + + + + +Rosenberg, et al. Standards Track [Page 39] + +RFC 5389 STUN October 2008 + + + Depending on the STUN usage, these attacks may be of minimal + consequence and thus do not require message integrity to mitigate. + For example, when STUN is used to a basic STUN server to discover a + server reflexive candidate for usage with ICE, authentication and + message integrity are not required since these attacks are detected + during the connectivity check phase. The connectivity checks + themselves, however, require protection for proper operation of ICE + overall. As described in Section 14, STUN usages describe when + authentication and message integrity are needed. + + Since STUN uses the HMAC of a shared secret for authentication and + integrity protection, it is subject to offline dictionary attacks. + When authentication is utilized, it SHOULD be with a strong password + that is not readily subject to offline dictionary attacks. + Protection of the channel itself, using TLS, mitigates these attacks. + However, STUN is most often run over UDP and in those cases, strong + passwords are the only way to protect against these attacks. + +16.1.2. Inside Attacks + + A rogue client may try to launch a DoS attack against a server by + sending it a large number of STUN requests. Fortunately, STUN + requests can be processed statelessly by a server, making such + attacks hard to launch. + + A rogue client may use a STUN server as a reflector, sending it + requests with a falsified source IP address and port. In such a + case, the response would be delivered to that source IP and port. + There is no amplification of the number of packets with this attack + (the STUN server sends one packet for each packet sent by the + client), though there is a small increase in the amount of data, + since STUN responses are typically larger than requests. This attack + is mitigated by ingress source address filtering. + + Revealing the specific software version of the agent through the + SOFTWARE attribute might allow them to become more vulnerable to + attacks against software that is known to contain security holes. + Implementers SHOULD make usage of the SOFTWARE attribute a + configurable option. + +16.2. Attacks Affecting the Usage + + This section lists attacks that might be launched against a usage of + STUN. Each STUN usage must consider whether these attacks are + applicable to it, and if so, discuss counter-measures. + + Most of the attacks in this section revolve around an attacker + modifying the reflexive address learned by a STUN client through a + + + +Rosenberg, et al. Standards Track [Page 40] + +RFC 5389 STUN October 2008 + + + Binding request/response transaction. Since the usage of the + reflexive address is a function of the usage, the applicability and + remediation of these attacks are usage-specific. In common + situations, modification of the reflexive address by an on-path + attacker is easy to do. Consider, for example, the common situation + where STUN is run directly over UDP. In this case, an on-path + attacker can modify the source IP address of the Binding request + before it arrives at the STUN server. The STUN server will then + return this IP address in the XOR-MAPPED-ADDRESS attribute to the + client, and send the response back to that (falsified) IP address and + port. If the attacker can also intercept this response, it can + direct it back towards the client. Protecting against this attack by + using a message-integrity check is impossible, since a message- + integrity value cannot cover the source IP address, since the + intervening NAT must be able to modify this value. Instead, one + solution to preventing the attacks listed below is for the client to + verify the reflexive address learned, as is done in ICE [MMUSIC-ICE]. + Other usages may use other means to prevent these attacks. + +16.2.1. Attack I: Distributed DoS (DDoS) against a Target + + In this attack, the attacker provides one or more clients with the + same faked reflexive address that points to the intended target. + This will trick the STUN clients into thinking that their reflexive + addresses are equal to that of the target. If the clients hand out + that reflexive address in order to receive traffic on it (for + example, in SIP messages), the traffic will instead be sent to the + target. This attack can provide substantial amplification, + especially when used with clients that are using STUN to enable + multimedia applications. However, it can only be launched against + targets for which packets from the STUN server to the target pass + through the attacker, limiting the cases in which it is possible. + +16.2.2. Attack II: Silencing a Client + + In this attack, the attacker provides a STUN client with a faked + reflexive address. The reflexive address it provides is a transport + address that routes to nowhere. As a result, the client won't + receive any of the packets it expects to receive when it hands out + the reflexive address. This exploitation is not very interesting for + the attacker. It impacts a single client, which is frequently not + the desired target. Moreover, any attacker that can mount the attack + could also deny service to the client by other means, such as + preventing the client from receiving any response from the STUN + server, or even a DHCP server. As with the attack in Section 16.2.1, + this attack is only possible when the attacker is on path for packets + sent from the STUN server towards this unused IP address. + + + + +Rosenberg, et al. Standards Track [Page 41] + +RFC 5389 STUN October 2008 + + +16.2.3. Attack III: Assuming the Identity of a Client + + This attack is similar to attack II. However, the faked reflexive + address points to the attacker itself. This allows the attacker to + receive traffic that was destined for the client. + +16.2.4. Attack IV: Eavesdropping + + In this attack, the attacker forces the client to use a reflexive + address that routes to itself. It then forwards any packets it + receives to the client. This attack would allow the attacker to + observe all packets sent to the client. However, in order to launch + the attack, the attacker must have already been able to observe + packets from the client to the STUN server. In most cases (such as + when the attack is launched from an access network), this means that + the attacker could already observe packets sent to the client. This + attack is, as a result, only useful for observing traffic by + attackers on the path from the client to the STUN server, but not + generally on the path of packets being routed towards the client. + +16.3. Hash Agility Plan + + This specification uses HMAC-SHA-1 for computation of the message + integrity. If, at a later time, HMAC-SHA-1 is found to be + compromised, the following is the remedy that will be applied. + + We will define a STUN extension that introduces a new message- + integrity attribute, computed using a new hash. Clients would be + required to include both the new and old message-integrity attributes + in their requests or indications. A new server will utilize the new + message-integrity attribute, and an old one, the old. After a + transition period where mixed implementations are in deployment, the + old message-integrity attribute will be deprecated by another + specification, and clients will cease including it in requests. + + It is also important to note that the HMAC is done using a key that + is itself computed using an MD5 of the user's password. The choice + of the MD5 hash was made because of the existence of legacy databases + that store passwords in that form. If future work finds that an HMAC + of an MD5 input is not secure, and a different hash is needed, it can + also be changed using this plan. However, this would require + administrators to repopulate their databases. + +17. IAB Considerations + + The IAB has studied the problem of Unilateral Self-Address Fixing + (UNSAF), which is the general process by which a client attempts to + determine its address in another realm on the other side of a NAT + + + +Rosenberg, et al. Standards Track [Page 42] + +RFC 5389 STUN October 2008 + + + through a collaborative protocol reflection mechanism (RFC3424 + [RFC3424]). STUN can be used to perform this function using a + Binding request/response transaction if one agent is behind a NAT and + the other is on the public side of the NAT. + + The IAB has mandated that protocols developed for this purpose + document a specific set of considerations. Because some STUN usages + provide UNSAF functions (such as ICE [MMUSIC-ICE] ), and others do + not (such as SIP Outbound [SIP-OUTBOUND]), answers to these + considerations need to be addressed by the usages themselves. + +18. IANA Considerations + + IANA has created three new registries: a "STUN Methods Registry", a + "STUN Attributes Registry", and a "STUN Error Codes Registry". IANA + has also changed the name of the assigned IANA port for STUN from + "nat-stun-port" to "stun". + +18.1. STUN Methods Registry + + A STUN method is a hex number in the range 0x000 - 0xFFF. The + encoding of STUN method into a STUN message is described in + Section 6. + + The initial STUN methods are: + + 0x000: (Reserved) + 0x001: Binding + 0x002: (Reserved; was SharedSecret) + + STUN methods in the range 0x000 - 0x7FF are assigned by IETF Review + [RFC5226]. STUN methods in the range 0x800 - 0xFFF are assigned by + Designated Expert [RFC5226]. The responsibility of the expert is to + verify that the selected codepoint(s) are not in use and that the + request is not for an abnormally large number of codepoints. + Technical review of the extension itself is outside the scope of the + designated expert responsibility. + +18.2. STUN Attribute Registry + + A STUN Attribute type is a hex number in the range 0x0000 - 0xFFFF. + STUN attribute types in the range 0x0000 - 0x7FFF are considered + comprehension-required; STUN attribute types in the range 0x8000 - + 0xFFFF are considered comprehension-optional. A STUN agent handles + unknown comprehension-required and comprehension-optional attributes + differently. + + The initial STUN Attributes types are: + + + +Rosenberg, et al. Standards Track [Page 43] + +RFC 5389 STUN October 2008 + + + Comprehension-required range (0x0000-0x7FFF): + 0x0000: (Reserved) + 0x0001: MAPPED-ADDRESS + 0x0002: (Reserved; was RESPONSE-ADDRESS) + 0x0003: (Reserved; was CHANGE-ADDRESS) + 0x0004: (Reserved; was SOURCE-ADDRESS) + 0x0005: (Reserved; was CHANGED-ADDRESS) + 0x0006: USERNAME + 0x0007: (Reserved; was PASSWORD) + 0x0008: MESSAGE-INTEGRITY + 0x0009: ERROR-CODE + 0x000A: UNKNOWN-ATTRIBUTES + 0x000B: (Reserved; was REFLECTED-FROM) + 0x0014: REALM + 0x0015: NONCE + 0x0020: XOR-MAPPED-ADDRESS + + Comprehension-optional range (0x8000-0xFFFF) + 0x8022: SOFTWARE + 0x8023: ALTERNATE-SERVER + 0x8028: FINGERPRINT + + STUN Attribute types in the first half of the comprehension-required + range (0x0000 - 0x3FFF) and in the first half of the comprehension- + optional range (0x8000 - 0xBFFF) are assigned by IETF Review + [RFC5226]. STUN Attribute types in the second half of the + comprehension-required range (0x4000 - 0x7FFF) and in the second half + of the comprehension-optional range (0xC000 - 0xFFFF) are assigned by + Designated Expert [RFC5226]. The responsibility of the expert is to + verify that the selected codepoint(s) are not in use, and that the + request is not for an abnormally large number of codepoints. + Technical review of the extension itself is outside the scope of the + designated expert responsibility. + +18.3. STUN Error Code Registry + + A STUN error code is a number in the range 0 - 699. STUN error codes + are accompanied by a textual reason phrase in UTF-8 [RFC3629] that is + intended only for human consumption and can be anything appropriate; + this document proposes only suggested values. + + STUN error codes are consistent in codepoint assignments and + semantics with SIP [RFC3261] and HTTP [RFC2616]. + + The initial values in this registry are given in Section 15.6. + + + + + + +Rosenberg, et al. Standards Track [Page 44] + +RFC 5389 STUN October 2008 + + + New STUN error codes are assigned based on IETF Review [RFC5226]. + The specification must carefully consider how clients that do not + understand this error code will process it before granting the + request. See the rules in Section 7.3.4. + +18.4. STUN UDP and TCP Port Numbers + + IANA has previously assigned port 3478 for STUN. This port appears + in the IANA registry under the moniker "nat-stun-port". In order to + align the DNS SRV procedures with the registered protocol service, + IANA is requested to change the name of protocol assigned to port + 3478 from "nat-stun-port" to "stun", and the textual name from + "Simple Traversal of UDP Through NAT (STUN)" to "Session Traversal + Utilities for NAT", so that the IANA port registry would read: + + stun 3478/tcp Session Traversal Utilities for NAT (STUN) port + stun 3478/udp Session Traversal Utilities for NAT (STUN) port + + In addition, IANA has assigned port number 5349 for the "stuns" + service, defined over TCP and UDP. The UDP port is not currently + defined; however, it is reserved for future use. + +19. Changes since RFC 3489 + + This specification obsoletes RFC 3489 [RFC3489]. This specification + differs from RFC 3489 in the following ways: + + o Removed the notion that STUN is a complete NAT traversal solution. + STUN is now a tool that can be used to produce a NAT traversal + solution. As a consequence, changed the name of the protocol to + Session Traversal Utilities for NAT. + + o Introduced the concept of STUN usages, and described what a usage + of STUN must document. + + o Removed the usage of STUN for NAT type detection and binding + lifetime discovery. These techniques have proven overly brittle + due to wider variations in the types of NAT devices than described + in this document. Removed the RESPONSE-ADDRESS, CHANGED-ADDRESS, + CHANGE-REQUEST, SOURCE-ADDRESS, and REFLECTED-FROM attributes. + + o Added a fixed 32-bit magic cookie and reduced length of + transaction ID by 32 bits. The magic cookie begins at the same + offset as the original transaction ID. + + + + + + + +Rosenberg, et al. Standards Track [Page 45] + +RFC 5389 STUN October 2008 + + + o Added the XOR-MAPPED-ADDRESS attribute, which is included in + Binding responses if the magic cookie is present in the request. + Otherwise, the RFC 3489 behavior is retained (that is, Binding + response includes MAPPED-ADDRESS). See discussion in XOR-MAPPED- + ADDRESS regarding this change. + + o Introduced formal structure into the message type header field, + with an explicit pair of bits for indication of request, response, + error response, or indication. Consequently, the message type + field is split into the class (one of the previous four) and + method. + + o Explicitly point out that the most significant 2 bits of STUN are + 0b00, allowing easy differentiation with RTP packets when used + with ICE. + + o Added the FINGERPRINT attribute to provide a method of definitely + detecting the difference between STUN and another protocol when + the two protocols are multiplexed together. + + o Added support for IPv6. Made it clear that an IPv4 client could + get a v6 mapped address, and vice versa. + + o Added long-term-credential-based authentication. + + o Added the SOFTWARE, REALM, NONCE, and ALTERNATE-SERVER attributes. + + o Removed the SharedSecret method, and thus the PASSWORD attribute. + This method was almost never implemented and is not needed with + current usages. + + o Removed recommendation to continue listening for STUN responses + for 10 seconds in an attempt to recognize an attack. + + o Changed transaction timers to be more TCP friendly. + + o Removed the STUN example that centered around the separation of + the control and media planes. Instead, provided more information + on using STUN with protocols. + + o Defined a generic padding mechanism that changes the + interpretation of the length attribute. This would, in theory, + break backwards compatibility. However, the mechanism in RFC 3489 + never worked for the few attributes that weren't aligned naturally + on 32-bit boundaries. + + o REALM, SERVER, reason phrases, and NONCE limited to 127 + characters. USERNAME to 513 bytes. + + + +Rosenberg, et al. Standards Track [Page 46] + +RFC 5389 STUN October 2008 + + + o Changed the DNS SRV procedures for TCP and TLS. UDP remains the + same as before. + +20. Contributors + + Christian Huitema and Joel Weinberger were original co-authors of RFC + 3489. + +21. Acknowledgements + + The authors would like to thank Cedric Aoun, Pete Cordell, Cullen + Jennings, Bob Penfield, Xavier Marjou, Magnus Westerlund, Miguel + Garcia, Bruce Lowekamp, and Chris Sullivan for their comments, and + Baruch Sterman and Alan Hawrylyshen for initial implementations. + Thanks for Leslie Daigle, Allison Mankin, Eric Rescorla, and Henning + Schulzrinne for IESG and IAB input on this work. + +22. References + +22.1. Normative References + + [ITU.V42.2002] International Telecommunications Union, "Error- + correcting Procedures for DCEs Using Asynchronous- + to-Synchronous Conversion", ITU-T Recommendation + V.42, March 2002. + + [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC1122] Braden, R., "Requirements for Internet Hosts - + Communication Layers", STD 3, RFC 1122, + October 1989. + + [RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", + RFC 1321, April 1992. + + [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: + Keyed-Hashing for Message Authentication", + RFC 2104, February 1997. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, + Version 6 (IPv6) Specification", RFC 2460, + December 1998. + + + + + +Rosenberg, et al. Standards Track [Page 47] + +RFC 5389 STUN October 2008 + + + [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., + Lawrence, S., Leach, P., Luotonen, A., and L. + Stewart, "HTTP Authentication: Basic and Digest + Access Authentication", RFC 2617, June 1999. + + [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS + RR for specifying the location of services (DNS + SRV)", RFC 2782, February 2000. + + [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000. + + [RFC2988] Paxson, V. and M. Allman, "Computing TCP's + Retransmission Timer", RFC 2988, November 2000. + + [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [RFC4013] Zeilenga, K., "SASLprep: Stringprep Profile for + User Names and Passwords", RFC 4013, February 2005. + +22.2. Informative References + + [BEHAVE-NAT] MacDonald, D. and B. Lowekamp, "NAT Behavior + Discovery Using STUN", Work in Progress, July 2008. + + [BEHAVE-TURN] Rosenberg, J., Mahy, R., and P. Matthews, + "Traversal Using Relays around NAT (TURN): Relay + Extensions to Session Traversal Utilities for NAT + (STUN)", Work in Progress, July 2008. + + [KARN87] Karn, P. and C. Partridge, "Improving Round-Trip + Time Estimates in Reliable Transport Protocols", + SIGCOMM 1987, August 1987. + + [MMUSIC-ICE] Rosenberg, J., "Interactive Connectivity + Establishment (ICE): A Protocol for Network Address + Translator (NAT) Traversal for Offer/Answer + Protocols", Work in Progress, October 2007. + + [MMUSIC-ICE-TCP] Rosenberg, J., "TCP Candidates with Interactive + Connectivity Establishment (ICE)", Work + in Progress, July 2008. + + [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., + Masinter, L., Leach, P., and T. Berners-Lee, + "Hypertext Transfer Protocol -- HTTP/1.1", + RFC 2616, June 1999. + + + + +Rosenberg, et al. Standards Track [Page 48] + +RFC 5389 STUN October 2008 + + + [RFC3261] Rosenberg, J., Schulzrinne, H., Camarillo, G., + Johnston, A., Peterson, J., Sparks, R., Handley, + M., and E. Schooler, "SIP: Session Initiation + Protocol", RFC 3261, June 2002. + + [RFC3264] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer + Model with Session Description Protocol (SDP)", + RFC 3264, June 2002. + + [RFC3424] Daigle, L. and IAB, "IAB Considerations for + UNilateral Self-Address Fixing (UNSAF) Across + Network Address Translation", RFC 3424, + November 2002. + + [RFC3489] Rosenberg, J., Weinberger, J., Huitema, C., and R. + Mahy, "STUN - Simple Traversal of User Datagram + Protocol (UDP) Through Network Address Translators + (NATs)", RFC 3489, March 2003. + + [RFC4107] Bellovin, S. and R. Housley, "Guidelines for + Cryptographic Key Management", BCP 107, RFC 4107, + June 2005. + + [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for + Writing an IANA Considerations Section in RFCs", + BCP 26, RFC 5226, May 2008. + + [SIP-OUTBOUND] Jennings, C. and R. Mahy, "Managing Client + Initiated Connections in the Session Initiation + Protocol (SIP)", Work in Progress, June 2008. + + + + + + + + + + + + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 49] + +RFC 5389 STUN October 2008 + + +Appendix A. C Snippet to Determine STUN Message Types + + Given a 16-bit STUN message type value in host byte order in msg_type + parameter, below are C macros to determine the STUN message types: + + #define IS_REQUEST(msg_type) (((msg_type) & 0x0110) == 0x0000) + #define IS_INDICATION(msg_type) (((msg_type) & 0x0110) == 0x0010) + #define IS_SUCCESS_RESP(msg_type) (((msg_type) & 0x0110) == 0x0100) + #define IS_ERR_RESP(msg_type) (((msg_type) & 0x0110) == 0x0110) + + +Authors' Addresses + + Jonathan Rosenberg + Cisco + Edison, NJ + US + + EMail: jdrosen@cisco.com + URI: http://www.jdrosen.net + + + Rohan Mahy + Unaffiliated + + EMail: rohan@ekabal.com + + + Philip Matthews + Unaffiliated + + EMail: philip_matthews@magma.ca + + + Dan Wing + Cisco + 771 Alder Drive + San Jose, CA 95035 + US + + EMail: dwing@cisco.com + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 50] + +RFC 5389 STUN October 2008 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2008). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + + + + + + + + + + + +Rosenberg, et al. Standards Track [Page 51] + diff --git a/docs/rfc5766-turn.txt b/docs/rfc5766-turn.txt new file mode 100644 index 0000000..f653035 --- /dev/null +++ b/docs/rfc5766-turn.txt @@ -0,0 +1,3755 @@ + + + + + + +Internet Engineering Task Force (IETF) R. Mahy +Request for Comments: 5766 Unaffiliated +Category: Standards Track P. Matthews +ISSN: 2070-1721 Alcatel-Lucent + J. Rosenberg + jdrosen.net + April 2010 + + + Traversal Using Relays around NAT (TURN): + Relay Extensions to Session Traversal Utilities for NAT (STUN) + +Abstract + + If a host is located behind a NAT, then in certain situations it can + be impossible for that host to communicate directly with other hosts + (peers). In these situations, it is necessary for the host to use + the services of an intermediate node that acts as a communication + relay. This specification defines a protocol, called TURN (Traversal + Using Relays around NAT), that allows the host to control the + operation of the relay and to exchange packets with its peers using + the relay. TURN differs from some other relay control protocols in + that it allows a client to communicate with multiple peers using a + single relay address. + + The TURN protocol was designed to be used as part of the ICE + (Interactive Connectivity Establishment) approach to NAT traversal, + though it also can be used without ICE. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc5766. + + + + + + + + + +Mahy, et al. Standards Track [Page 1] + +RFC 5766 TURN April 2010 + + +Copyright Notice + + Copyright (c) 2010 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Overview of Operation . . . . . . . . . . . . . . . . . . . . 5 + 2.1. Transports . . . . . . . . . . . . . . . . . . . . . . . . 8 + 2.2. Allocations . . . . . . . . . . . . . . . . . . . . . . . 9 + 2.3. Permissions . . . . . . . . . . . . . . . . . . . . . . . 11 + 2.4. Send Mechanism . . . . . . . . . . . . . . . . . . . . . . 12 + 2.5. Channels . . . . . . . . . . . . . . . . . . . . . . . . . 13 + 2.6. Unprivileged TURN Servers . . . . . . . . . . . . . . . . 15 + 2.7. Avoiding IP Fragmentation . . . . . . . . . . . . . . . . 16 + 2.8. RTP Support . . . . . . . . . . . . . . . . . . . . . . . 17 + 2.9. Anycast Discovery of Servers . . . . . . . . . . . . . . . 17 + 3. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 18 + 4. General Behavior . . . . . . . . . . . . . . . . . . . . . . . 19 + 5. Allocations . . . . . . . . . . . . . . . . . . . . . . . . . 22 + 6. Creating an Allocation . . . . . . . . . . . . . . . . . . . . 23 + 6.1. Sending an Allocate Request . . . . . . . . . . . . . . . 23 + 6.2. Receiving an Allocate Request . . . . . . . . . . . . . . 24 + 6.3. Receiving an Allocate Success Response . . . . . . . . . . 28 + 6.4. Receiving an Allocate Error Response . . . . . . . . . . . 29 + 7. Refreshing an Allocation . . . . . . . . . . . . . . . . . . . 31 + 7.1. Sending a Refresh Request . . . . . . . . . . . . . . . . 31 + 7.2. Receiving a Refresh Request . . . . . . . . . . . . . . . 31 + 7.3. Receiving a Refresh Response . . . . . . . . . . . . . . . 32 + 8. Permissions . . . . . . . . . . . . . . . . . . . . . . . . . 32 + 9. CreatePermission . . . . . . . . . . . . . . . . . . . . . . . 34 + 9.1. Forming a CreatePermission Request . . . . . . . . . . . . 34 + 9.2. Receiving a CreatePermission Request . . . . . . . . . . . 34 + 9.3. Receiving a CreatePermission Response . . . . . . . . . . 35 + 10. Send and Data Methods . . . . . . . . . . . . . . . . . . . . 35 + 10.1. Forming a Send Indication . . . . . . . . . . . . . . . . 35 + 10.2. Receiving a Send Indication . . . . . . . . . . . . . . . 35 + + + +Mahy, et al. Standards Track [Page 2] + +RFC 5766 TURN April 2010 + + + 10.3. Receiving a UDP Datagram . . . . . . . . . . . . . . . . . 36 + 10.4. Receiving a Data Indication . . . . . . . . . . . . . . . 37 + 11. Channels . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 + 11.1. Sending a ChannelBind Request . . . . . . . . . . . . . . 39 + 11.2. Receiving a ChannelBind Request . . . . . . . . . . . . . 39 + 11.3. Receiving a ChannelBind Response . . . . . . . . . . . . . 40 + 11.4. The ChannelData Message . . . . . . . . . . . . . . . . . 41 + 11.5. Sending a ChannelData Message . . . . . . . . . . . . . . 41 + 11.6. Receiving a ChannelData Message . . . . . . . . . . . . . 42 + 11.7. Relaying Data from the Peer . . . . . . . . . . . . . . . 43 + 12. IP Header Fields . . . . . . . . . . . . . . . . . . . . . . . 43 + 13. New STUN Methods . . . . . . . . . . . . . . . . . . . . . . . 45 + 14. New STUN Attributes . . . . . . . . . . . . . . . . . . . . . 45 + 14.1. CHANNEL-NUMBER . . . . . . . . . . . . . . . . . . . . . . 45 + 14.2. LIFETIME . . . . . . . . . . . . . . . . . . . . . . . . . 46 + 14.3. XOR-PEER-ADDRESS . . . . . . . . . . . . . . . . . . . . . 46 + 14.4. DATA . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 + 14.5. XOR-RELAYED-ADDRESS . . . . . . . . . . . . . . . . . . . 46 + 14.6. EVEN-PORT . . . . . . . . . . . . . . . . . . . . . . . . 46 + 14.7. REQUESTED-TRANSPORT . . . . . . . . . . . . . . . . . . . 47 + 14.8. DONT-FRAGMENT . . . . . . . . . . . . . . . . . . . . . . 47 + 14.9. RESERVATION-TOKEN . . . . . . . . . . . . . . . . . . . . 48 + 15. New STUN Error Response Codes . . . . . . . . . . . . . . . . 48 + 16. Detailed Example . . . . . . . . . . . . . . . . . . . . . . . 48 + 17. Security Considerations . . . . . . . . . . . . . . . . . . . 55 + 17.1. Outsider Attacks . . . . . . . . . . . . . . . . . . . . . 55 + 17.1.1. Obtaining Unauthorized Allocations . . . . . . . . . 55 + 17.1.2. Offline Dictionary Attacks . . . . . . . . . . . . . 56 + 17.1.3. Faked Refreshes and Permissions . . . . . . . . . . . 56 + 17.1.4. Fake Data . . . . . . . . . . . . . . . . . . . . . . 56 + 17.1.5. Impersonating a Server . . . . . . . . . . . . . . . 57 + 17.1.6. Eavesdropping Traffic . . . . . . . . . . . . . . . . 58 + 17.1.7. TURN Loop Attack . . . . . . . . . . . . . . . . . . 58 + 17.2. Firewall Considerations . . . . . . . . . . . . . . . . . 59 + 17.2.1. Faked Permissions . . . . . . . . . . . . . . . . . . 59 + 17.2.2. Blacklisted IP Addresses . . . . . . . . . . . . . . 60 + 17.2.3. Running Servers on Well-Known Ports . . . . . . . . . 60 + 17.3. Insider Attacks . . . . . . . . . . . . . . . . . . . . . 60 + 17.3.1. DoS against TURN Server . . . . . . . . . . . . . . . 60 + 17.3.2. Anonymous Relaying of Malicious Traffic . . . . . . . 61 + 17.3.3. Manipulating Other Allocations . . . . . . . . . . . 61 + 17.4. Other Considerations . . . . . . . . . . . . . . . . . . . 61 + 18. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 61 + 19. IAB Considerations . . . . . . . . . . . . . . . . . . . . . . 62 + 20. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 63 + 21. References . . . . . . . . . . . . . . . . . . . . . . . . . . 64 + 21.1. Normative References . . . . . . . . . . . . . . . . . . . 64 + 21.2. Informative References . . . . . . . . . . . . . . . . . . 64 + + + +Mahy, et al. Standards Track [Page 3] + +RFC 5766 TURN April 2010 + + +1. Introduction + + A host behind a NAT may wish to exchange packets with other hosts, + some of which may also be behind NATs. To do this, the hosts + involved can use "hole punching" techniques (see [RFC5128]) in an + attempt discover a direct communication path; that is, a + communication path that goes from one host to another through + intervening NATs and routers, but does not traverse any relays. + + As described in [RFC5128] and [RFC4787], hole punching techniques + will fail if both hosts are behind NATs that are not well behaved. + For example, if both hosts are behind NATs that have a mapping + behavior of "address-dependent mapping" or "address- and port- + dependent mapping", then hole punching techniques generally fail. + + When a direct communication path cannot be found, it is necessary to + use the services of an intermediate host that acts as a relay for the + packets. This relay typically sits in the public Internet and relays + packets between two hosts that both sit behind NATs. + + This specification defines a protocol, called TURN, that allows a + host behind a NAT (called the TURN client) to request that another + host (called the TURN server) act as a relay. The client can arrange + for the server to relay packets to and from certain other hosts + (called peers) and can control aspects of how the relaying is done. + The client does this by obtaining an IP address and port on the + server, called the relayed transport address. When a peer sends a + packet to the relayed transport address, the server relays the packet + to the client. When the client sends a data packet to the server, + the server relays it to the appropriate peer using the relayed + transport address as the source. + + A client using TURN must have some way to communicate the relayed + transport address to its peers, and to learn each peer's IP address + and port (more precisely, each peer's server-reflexive transport + address, see Section 2). How this is done is out of the scope of the + TURN protocol. One way this might be done is for the client and + peers to exchange email messages. Another way is for the client and + its peers to use a special-purpose "introduction" or "rendezvous" + protocol (see [RFC5128] for more details). + + If TURN is used with ICE [RFC5245], then the relayed transport + address and the IP addresses and ports of the peers are included in + the ICE candidate information that the rendezvous protocol must + carry. For example, if TURN and ICE are used as part of a multimedia + solution using SIP [RFC3261], then SIP serves the role of the + rendezvous protocol, carrying the ICE candidate information inside + the body of SIP messages. If TURN and ICE are used with some other + + + +Mahy, et al. Standards Track [Page 4] + +RFC 5766 TURN April 2010 + + + rendezvous protocol, then [MMUSIC-ICE-NONSIP] provides guidance on + the services the rendezvous protocol must perform. + + Though the use of a TURN server to enable communication between two + hosts behind NATs is very likely to work, it comes at a high cost to + the provider of the TURN server, since the server typically needs a + high-bandwidth connection to the Internet. As a consequence, it is + best to use a TURN server only when a direct communication path + cannot be found. When the client and a peer use ICE to determine the + communication path, ICE will use hole punching techniques to search + for a direct path first and only use a TURN server when a direct path + cannot be found. + + TURN was originally invented to support multimedia sessions signaled + using SIP. Since SIP supports forking, TURN supports multiple peers + per relayed transport address; a feature not supported by other + approaches (e.g., SOCKS [RFC1928]). However, care has been taken to + make sure that TURN is suitable for other types of applications. + + TURN was designed as one piece in the larger ICE approach to NAT + traversal. Implementors of TURN are urged to investigate ICE and + seriously consider using it for their application. However, it is + possible to use TURN without ICE. + + TURN is an extension to the STUN (Session Traversal Utilities for + NAT) protocol [RFC5389]. Most, though not all, TURN messages are + STUN-formatted messages. A reader of this document should be + familiar with STUN. + +2. Overview of Operation + + This section gives an overview of the operation of TURN. It is non- + normative. + + In a typical configuration, a TURN client is connected to a private + network [RFC1918] and through one or more NATs to the public + Internet. On the public Internet is a TURN server. Elsewhere in the + Internet are one or more peers with which the TURN client wishes to + communicate. These peers may or may not be behind one or more NATs. + The client uses the server as a relay to send packets to these peers + and to receive packets from these peers. + + + + + + + + + + +Mahy, et al. Standards Track [Page 5] + +RFC 5766 TURN April 2010 + + + Peer A + Server-Reflexive +---------+ + Transport Address | | + 192.0.2.150:32102 | | + | /| | + TURN | / ^| Peer A | + Client's Server | / || | + Host Transport Transport | // || | + Address Address | // |+---------+ + 10.1.1.2:49721 192.0.2.15:3478 |+-+ // Peer A + | | ||N| / Host Transport + | +-+ | ||A|/ Address + | | | | v|T| 192.168.100.2:49582 + | | | | /+-+ + +---------+| | | |+---------+ / +---------+ + | || |N| || | // | | + | TURN |v | | v| TURN |/ | | + | Client |----|A|----------| Server |------------------| Peer B | + | | | |^ | |^ ^| | + | | |T|| | || || | + +---------+ | || +---------+| |+---------+ + | || | | + | || | | + +-+| | | + | | | + | | | + Client's | Peer B + Server-Reflexive Relayed Transport + Transport Address Transport Address Address + 192.0.2.1:7000 192.0.2.15:50000 192.0.2.210:49191 + + Figure 1 + + Figure 1 shows a typical deployment. In this figure, the TURN client + and the TURN server are separated by a NAT, with the client on the + private side and the server on the public side of the NAT. This NAT + is assumed to be a "bad" NAT; for example, it might have a mapping + property of "address-and-port-dependent mapping" (see [RFC4787]). + + The client talks to the server from a (IP address, port) combination + called the client's HOST TRANSPORT ADDRESS. (The combination of an + IP address and port is called a TRANSPORT ADDRESS.) + + The client sends TURN messages from its host transport address to a + transport address on the TURN server that is known as the TURN SERVER + TRANSPORT ADDRESS. The client learns the TURN server transport + address through some unspecified means (e.g., configuration), and + this address is typically used by many clients simultaneously. + + + +Mahy, et al. Standards Track [Page 6] + +RFC 5766 TURN April 2010 + + + Since the client is behind a NAT, the server sees packets from the + client as coming from a transport address on the NAT itself. This + address is known as the client's SERVER-REFLEXIVE transport address; + packets sent by the server to the client's server-reflexive transport + address will be forwarded by the NAT to the client's host transport + address. + + The client uses TURN commands to create and manipulate an ALLOCATION + on the server. An allocation is a data structure on the server. + This data structure contains, amongst other things, the RELAYED + TRANSPORT ADDRESS for the allocation. The relayed transport address + is the transport address on the server that peers can use to have the + server relay data to the client. An allocation is uniquely + identified by its relayed transport address. + + Once an allocation is created, the client can send application data + to the server along with an indication of to which peer the data is + to be sent, and the server will relay this data to the appropriate + peer. The client sends the application data to the server inside a + TURN message; at the server, the data is extracted from the TURN + message and sent to the peer in a UDP datagram. In the reverse + direction, a peer can send application data in a UDP datagram to the + relayed transport address for the allocation; the server will then + encapsulate this data inside a TURN message and send it to the client + along with an indication of which peer sent the data. Since the TURN + message always contains an indication of which peer the client is + communicating with, the client can use a single allocation to + communicate with multiple peers. + + When the peer is behind a NAT, then the client must identify the peer + using its server-reflexive transport address rather than its host + transport address. For example, to send application data to Peer A + in the example above, the client must specify 192.0.2.150:32102 (Peer + A's server-reflexive transport address) rather than 192.168.100.2: + 49582 (Peer A's host transport address). + + Each allocation on the server belongs to a single client and has + exactly one relayed transport address that is used only by that + allocation. Thus, when a packet arrives at a relayed transport + address on the server, the server knows for which client the data is + intended. + + The client may have multiple allocations on a server at the same + time. + + + + + + + +Mahy, et al. Standards Track [Page 7] + +RFC 5766 TURN April 2010 + + +2.1. Transports + + TURN, as defined in this specification, always uses UDP between the + server and the peer. However, this specification allows the use of + any one of UDP, TCP, or Transport Layer Security (TLS) over TCP to + carry the TURN messages between the client and the server. + + +----------------------------+---------------------+ + | TURN client to TURN server | TURN server to peer | + +----------------------------+---------------------+ + | UDP | UDP | + | TCP | UDP | + | TLS over TCP | UDP | + +----------------------------+---------------------+ + + If TCP or TLS-over-TCP is used between the client and the server, + then the server will convert between these transports and UDP + transport when relaying data to/from the peer. + + Since this version of TURN only supports UDP between the server and + the peer, it is expected that most clients will prefer to use UDP + between the client and the server as well. That being the case, some + readers may wonder: Why also support TCP and TLS-over-TCP? + + TURN supports TCP transport between the client and the server because + some firewalls are configured to block UDP entirely. These firewalls + block UDP but not TCP, in part because TCP has properties that make + the intention of the nodes being protected by the firewall more + obvious to the firewall. For example, TCP has a three-way handshake + that makes in clearer that the protected node really wishes to have + that particular connection established, while for UDP the best the + firewall can do is guess which flows are desired by using filtering + rules. Also, TCP has explicit connection teardown; while for UDP, + the firewall has to use timers to guess when the flow is finished. + + TURN supports TLS-over-TCP transport between the client and the + server because TLS provides additional security properties not + provided by TURN's default digest authentication; properties that + some clients may wish to take advantage of. In particular, TLS + provides a way for the client to ascertain that it is talking to the + correct server, and provides for confidentiality of TURN control + messages. TURN does not require TLS because the overhead of using + TLS is higher than that of digest authentication; for example, using + TLS likely means that most application data will be doubly encrypted + (once by TLS and once to ensure it is still encrypted in the UDP + datagram). + + + + + +Mahy, et al. Standards Track [Page 8] + +RFC 5766 TURN April 2010 + + + There is a planned extension to TURN to add support for TCP between + the server and the peers [TURN-TCP]. For this reason, allocations + that use UDP between the server and the peers are known as UDP + allocations, while allocations that use TCP between the server and + the peers are known as TCP allocations. This specification describes + only UDP allocations. + + TURN, as defined in this specification, only supports IPv4. All IP + addresses in this specification must be IPv4 addresses. There is a + planned extension to TURN to add support for IPv6 and for relaying + between IPv4 and IPv6 [TURN-IPv6]. + + In some applications for TURN, the client may send and receive + packets other than TURN packets on the host transport address it uses + to communicate with the server. This can happen, for example, when + using TURN with ICE. In these cases, the client can distinguish TURN + packets from other packets by examining the source address of the + arriving packet: those arriving from the TURN server will be TURN + packets. + +2.2. Allocations + + To create an allocation on the server, the client uses an Allocate + transaction. The client sends an Allocate request to the server, and + the server replies with an Allocate success response containing the + allocated relayed transport address. The client can include + attributes in the Allocate request that describe the type of + allocation it desires (e.g., the lifetime of the allocation). Since + relaying data has security implications, the server requires that the + client authenticate itself, typically using STUN's long-term + credential mechanism, to show that it is authorized to use the + server. + + Once a relayed transport address is allocated, a client must keep the + allocation alive. To do this, the client periodically sends a + Refresh request to the server. TURN deliberately uses a different + method (Refresh rather than Allocate) for refreshes to ensure that + the client is informed if the allocation vanishes for some reason. + + The frequency of the Refresh transaction is determined by the + lifetime of the allocation. The default lifetime of an allocation is + 10 minutes -- this value was chosen to be long enough so that + refreshing is not typically a burden on the client, while expiring + allocations where the client has unexpectedly quit in a timely + manner. However, the client can request a longer lifetime in the + Allocate request and may modify its request in a Refresh request, and + the server always indicates the actual lifetime in the response. The + client must issue a new Refresh transaction within "lifetime" seconds + + + +Mahy, et al. Standards Track [Page 9] + +RFC 5766 TURN April 2010 + + + of the previous Allocate or Refresh transaction. Once a client no + longer wishes to use an allocation, it should delete the allocation + using a Refresh request with a requested lifetime of 0. + + Both the server and client keep track of a value known as the + 5-TUPLE. At the client, the 5-tuple consists of the client's host + transport address, the server transport address, and the transport + protocol used by the client to communicate with the server. At the + server, the 5-tuple value is the same except that the client's host + transport address is replaced by the client's server-reflexive + address, since that is the client's address as seen by the server. + + Both the client and the server remember the 5-tuple used in the + Allocate request. Subsequent messages between the client and the + server use the same 5-tuple. In this way, the client and server know + which allocation is being referred to. If the client wishes to + allocate a second relayed transport address, it must create a second + allocation using a different 5-tuple (e.g., by using a different + client host address or port). + + NOTE: While the terminology used in this document refers to + 5-tuples, the TURN server can store whatever identifier it likes + that yields identical results. Specifically, an implementation + may use a file-descriptor in place of a 5-tuple to represent a TCP + connection. + + TURN TURN Peer Peer + client server A B + |-- Allocate request --------------->| | | + | | | | + |<--------------- Allocate failure --| | | + | (401 Unauthorized) | | | + | | | | + |-- Allocate request --------------->| | | + | | | | + |<---------- Allocate success resp --| | | + | (192.0.2.15:50000) | | | + // // // // + | | | | + |-- Refresh request ---------------->| | | + | | | | + |<----------- Refresh success resp --| | | + | | | | + + Figure 2 + + + + + + +Mahy, et al. Standards Track [Page 10] + +RFC 5766 TURN April 2010 + + + In Figure 2, the client sends an Allocate request to the server + without credentials. Since the server requires that all requests be + authenticated using STUN's long-term credential mechanism, the server + rejects the request with a 401 (Unauthorized) error code. The client + then tries again, this time including credentials (not shown). This + time, the server accepts the Allocate request and returns an Allocate + success response containing (amongst other things) the relayed + transport address assigned to the allocation. Sometime later, the + client decides to refresh the allocation and thus sends a Refresh + request to the server. The refresh is accepted and the server + replies with a Refresh success response. + +2.3. Permissions + + To ease concerns amongst enterprise IT administrators that TURN could + be used to bypass corporate firewall security, TURN includes the + notion of permissions. TURN permissions mimic the address-restricted + filtering mechanism of NATs that comply with [RFC4787]. + + An allocation can have zero or more permissions. Each permission + consists of an IP address and a lifetime. When the server receives a + UDP datagram on the allocation's relayed transport address, it first + checks the list of permissions. If the source IP address of the + datagram matches a permission, the application data is relayed to the + client, otherwise the UDP datagram is silently discarded. + + A permission expires after 5 minutes if it is not refreshed, and + there is no way to explicitly delete a permission. This behavior was + selected to match the behavior of a NAT that complies with [RFC4787]. + + The client can install or refresh a permission using either a + CreatePermission request or a ChannelBind request. Using the + CreatePermission request, multiple permissions can be installed or + refreshed with a single request -- this is important for applications + that use ICE. For security reasons, permissions can only be + installed or refreshed by transactions that can be authenticated; + thus, Send indications and ChannelData messages (which are used to + send data to peers) do not install or refresh any permissions. + + Note that permissions are within the context of an allocation, so + adding or expiring a permission in one allocation does not affect + other allocations. + + + + + + + + + +Mahy, et al. Standards Track [Page 11] + +RFC 5766 TURN April 2010 + + +2.4. Send Mechanism + + There are two mechanisms for the client and peers to exchange + application data using the TURN server. The first mechanism uses the + Send and Data methods, the second way uses channels. Common to both + ways is the ability of the client to communicate with multiple peers + using a single allocated relayed transport address; thus, both ways + include a means for the client to indicate to the server which peer + should receive the data, and for the server to indicate to the client + which peer sent the data. + + The Send mechanism uses Send and Data indications. Send indications + are used to send application data from the client to the server, + while Data indications are used to send application data from the + server to the client. + + When using the Send mechanism, the client sends a Send indication to + the TURN server containing (a) an XOR-PEER-ADDRESS attribute + specifying the (server-reflexive) transport address of the peer and + (b) a DATA attribute holding the application data. When the TURN + server receives the Send indication, it extracts the application data + from the DATA attribute and sends it in a UDP datagram to the peer, + using the allocated relay address as the source address. Note that + there is no need to specify the relayed transport address, since it + is implied by the 5-tuple used for the Send indication. + + In the reverse direction, UDP datagrams arriving at the relayed + transport address on the TURN server are converted into Data + indications and sent to the client, with the server-reflexive + transport address of the peer included in an XOR-PEER-ADDRESS + attribute and the data itself in a DATA attribute. Since the relayed + transport address uniquely identified the allocation, the server + knows which client should receive the data. + + Send and Data indications cannot be authenticated, since the long- + term credential mechanism of STUN does not support authenticating + indications. This is not as big an issue as it might first appear, + since the client-to-server leg is only half of the total path to the + peer. Applications that want proper security should encrypt the data + sent between the client and a peer. + + Because Send indications are not authenticated, it is possible for an + attacker to send bogus Send indications to the server, which will + then relay these to a peer. To partly mitigate this attack, TURN + requires that the client install a permission towards a peer before + sending data to it using a Send indication. + + + + + +Mahy, et al. Standards Track [Page 12] + +RFC 5766 TURN April 2010 + + + TURN TURN Peer Peer + client server A B + | | | | + |-- CreatePermission req (Peer A) -->| | | + |<-- CreatePermission success resp --| | | + | | | | + |--- Send ind (Peer A)-------------->| | | + | |=== data ===>| | + | | | | + | |<== data ====| | + |<-------------- Data ind (Peer A) --| | | + | | | | + | | | | + |--- Send ind (Peer B)-------------->| | | + | | dropped | | + | | | | + | |<== data ==================| + | dropped | | | + | | | | + + Figure 3 + + In Figure 3, the client has already created an allocation and now + wishes to send data to its peers. The client first creates a + permission by sending the server a CreatePermission request + specifying Peer A's (server-reflexive) IP address in the XOR-PEER- + ADDRESS attribute; if this was not done, the server would not relay + data between the client and the server. The client then sends data + to Peer A using a Send indication; at the server, the application + data is extracted and forwarded in a UDP datagram to Peer A, using + the relayed transport address as the source transport address. When + a UDP datagram from Peer A is received at the relayed transport + address, the contents are placed into a Data indication and forwarded + to the client. Later, the client attempts to exchange data with Peer + B; however, no permission has been installed for Peer B, so the Send + indication from the client and the UDP datagram from the peer are + both dropped by the server. + +2.5. Channels + + For some applications (e.g., Voice over IP), the 36 bytes of overhead + that a Send indication or Data indication adds to the application + data can substantially increase the bandwidth required between the + client and the server. To remedy this, TURN offers a second way for + the client and server to associate data with a specific peer. + + This second way uses an alternate packet format known as the + ChannelData message. The ChannelData message does not use the STUN + + + +Mahy, et al. Standards Track [Page 13] + +RFC 5766 TURN April 2010 + + + header used by other TURN messages, but instead has a 4-byte header + that includes a number known as a channel number. Each channel + number in use is bound to a specific peer and thus serves as a + shorthand for the peer's host transport address. + + To bind a channel to a peer, the client sends a ChannelBind request + to the server, and includes an unbound channel number and the + transport address of the peer. Once the channel is bound, the client + can use a ChannelData message to send the server data destined for + the peer. Similarly, the server can relay data from that peer + towards the client using a ChannelData message. + + Channel bindings last for 10 minutes unless refreshed -- this + lifetime was chosen to be longer than the permission lifetime. + Channel bindings are refreshed by sending another ChannelBind request + rebinding the channel to the peer. Like permissions (but unlike + allocations), there is no way to explicitly delete a channel binding; + the client must simply wait for it to time out. + + TURN TURN Peer Peer + client server A B + | | | | + |-- ChannelBind req ---------------->| | | + | (Peer A to 0x4001) | | | + | | | | + |<---------- ChannelBind succ resp --| | | + | | | | + |-- [0x4001] data ------------------>| | | + | |=== data ===>| | + | | | | + | |<== data ====| | + |<------------------ [0x4001] data --| | | + | | | | + |--- Send ind (Peer A)-------------->| | | + | |=== data ===>| | + | | | | + | |<== data ====| | + |<------------------ [0x4001] data --| | | + | | | | + + Figure 4 + + Figure 4 shows the channel mechanism in use. The client has already + created an allocation and now wishes to bind a channel to Peer A. To + do this, the client sends a ChannelBind request to the server, + specifying the transport address of Peer A and a channel number + (0x4001). After that, the client can send application data + encapsulated inside ChannelData messages to Peer A: this is shown as + + + +Mahy, et al. Standards Track [Page 14] + +RFC 5766 TURN April 2010 + + + "[0x4001] data" where 0x4001 is the channel number. When the + ChannelData message arrives at the server, the server transfers the + data to a UDP datagram and sends it to Peer A (which is the peer + bound to channel number 0x4001). + + In the reverse direction, when Peer A sends a UDP datagram to the + relayed transport address, this UDP datagram arrives at the server on + the relayed transport address assigned to the allocation. Since the + UDP datagram was received from Peer A, which has a channel number + assigned to it, the server encapsulates the data into a ChannelData + message when sending the data to the client. + + Once a channel has been bound, the client is free to intermix + ChannelData messages and Send indications. In the figure, the client + later decides to use a Send indication rather than a ChannelData + message to send additional data to Peer A. The client might decide + to do this, for example, so it can use the DONT-FRAGMENT attribute + (see the next section). However, once a channel is bound, the server + will always use a ChannelData message, as shown in the call flow. + + Note that ChannelData messages can only be used for peers to which + the client has bound a channel. In the example above, Peer A has + been bound to a channel, but Peer B has not, so application data to + and from Peer B would use the Send mechanism. + +2.6. Unprivileged TURN Servers + + This version of TURN is designed so that the server can be + implemented as an application that runs in user space under commonly + available operating systems without requiring special privileges. + This design decision was made to make it easy to deploy a TURN + server: for example, to allow a TURN server to be integrated into a + peer-to-peer application so that one peer can offer NAT traversal + services to another peer. + + This design decision has the following implications for data relayed + by a TURN server: + + o The value of the Diffserv field may not be preserved across the + server; + + o The Time to Live (TTL) field may be reset, rather than + decremented, across the server; + + o The Explicit Congestion Notification (ECN) field may be reset by + the server; + + o ICMP messages are not relayed by the server; + + + +Mahy, et al. Standards Track [Page 15] + +RFC 5766 TURN April 2010 + + + o There is no end-to-end fragmentation, since the packet is re- + assembled at the server. + + Future work may specify alternate TURN semantics that address these + limitations. + +2.7. Avoiding IP Fragmentation + + For reasons described in [Frag-Harmful], applications, especially + those sending large volumes of data, should try hard to avoid having + their packets fragmented. Applications using TCP can more or less + ignore this issue because fragmentation avoidance is now a standard + part of TCP, but applications using UDP (and thus any application + using this version of TURN) must handle fragmentation avoidance + themselves. + + The application running on the client and the peer can take one of + two approaches to avoid IP fragmentation. + + The first approach is to avoid sending large amounts of application + data in the TURN messages/UDP datagrams exchanged between the client + and the peer. This is the approach taken by most VoIP + (Voice-over-IP) applications. In this approach, the application + exploits the fact that the IP specification [RFC0791] specifies that + IP packets up to 576 bytes should never need to be fragmented. + + The exact amount of application data that can be included while + avoiding fragmentation depends on the details of the TURN session + between the client and the server: whether UDP, TCP, or TLS transport + is used, whether ChannelData messages or Send/Data indications are + used, and whether any additional attributes (such as the DONT- + FRAGMENT attribute) are included. Another factor, which is hard to + determine, is whether the MTU is reduced somewhere along the path for + other reasons, such as the use of IP-in-IP tunneling. + + As a guideline, sending a maximum of 500 bytes of application data in + a single TURN message (by the client on the client-to-server leg) or + a UDP datagram (by the peer on the peer-to-server leg) will generally + avoid IP fragmentation. To further reduce the chance of + fragmentation, it is recommended that the client use ChannelData + messages when transferring significant volumes of data, since the + overhead of the ChannelData message is less than Send and Data + indications. + + The second approach the client and peer can take to avoid + fragmentation is to use a path MTU discovery algorithm to determine + the maximum amount of application data that can be sent without + fragmentation. + + + +Mahy, et al. Standards Track [Page 16] + +RFC 5766 TURN April 2010 + + + Unfortunately, because servers implementing this version of TURN do + not relay ICMP messages, the classic path MTU discovery algorithm + defined in [RFC1191] is not able to discover the MTU of the + transmission path between the client and the peer. (Even if they did + relay ICMP messages, the algorithm would not always work since ICMP + messages are often filtered out by combined NAT/firewall devices). + + So the client and server need to use a path MTU discovery algorithm + that does not require ICMP messages. The Packetized Path MTU + Discovery algorithm defined in [RFC4821] is one such algorithm. + + The details of how to use the algorithm of [RFC4821] with TURN are + still under investigation. However, as a step towards this goal, + this version of TURN supports a DONT-FRAGMENT attribute. When the + client includes this attribute in a Send indication, this tells the + server to set the DF bit in the resulting UDP datagram that it sends + to the peer. Since some servers may be unable to set the DF bit, the + client should also include this attribute in the Allocate request -- + any server that does not support the DONT-FRAGMENT attribute will + indicate this by rejecting the Allocate request. + +2.8. RTP Support + + One of the envisioned uses of TURN is as a relay for clients and + peers wishing to exchange real-time data (e.g., voice or video) using + RTP. To facilitate the use of TURN for this purpose, TURN includes + some special support for older versions of RTP. + + Old versions of RTP [RFC3550] required that the RTP stream be on an + even port number and the associated RTP Control Protocol (RTCP) + stream, if present, be on the next highest port. To allow clients to + work with peers that still require this, TURN allows the client to + request that the server allocate a relayed transport address with an + even port number, and to optionally request the server reserve the + next-highest port number for a subsequent allocation. + +2.9. Anycast Discovery of Servers + + This version of TURN has been designed to permit the future + specification of a method of doing anycast discovery of a TURN server + over UDP. + + Specifically, a TURN server can reject an Allocate request with the + suggestion that the client try an alternate server. To avoid certain + types of attacks, the client must use the same credentials with the + alternate server as it would have with the initial server. + + + + + +Mahy, et al. Standards Track [Page 17] + +RFC 5766 TURN April 2010 + + +3. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [RFC2119]. + + Readers are expected to be familiar with [RFC5389] and the terms + defined there. + + The following terms are used in this document: + + TURN: The protocol spoken between a TURN client and a TURN server. + It is an extension to the STUN protocol [RFC5389]. The protocol + allows a client to allocate and use a relayed transport address. + + TURN client: A STUN client that implements this specification. + + TURN server: A STUN server that implements this specification. It + relays data between a TURN client and its peer(s). + + Peer: A host with which the TURN client wishes to communicate. The + TURN server relays traffic between the TURN client and its + peer(s). The peer does not interact with the TURN server using + the protocol defined in this document; rather, the peer receives + data sent by the TURN server and the peer sends data towards the + TURN server. + + Transport Address: The combination of an IP address and a port. + + Host Transport Address: A transport address on a client or a peer. + + Server-Reflexive Transport Address: A transport address on the + "public side" of a NAT. This address is allocated by the NAT to + correspond to a specific host transport address. + + Relayed Transport Address: A transport address on the TURN server + that is used for relaying packets between the client and a peer. + A peer sends to this address on the TURN server, and the packet is + then relayed to the client. + + TURN Server Transport Address: A transport address on the TURN + server that is used for sending TURN messages to the server. This + is the transport address that the client uses to communicate with + the server. + + Peer Transport Address: The transport address of the peer as seen by + the server. When the peer is behind a NAT, this is the peer's + server-reflexive transport address. + + + +Mahy, et al. Standards Track [Page 18] + +RFC 5766 TURN April 2010 + + + Allocation: The relayed transport address granted to a client + through an Allocate request, along with related state, such as + permissions and expiration timers. + + 5-tuple: The combination (client IP address and port, server IP + address and port, and transport protocol (currently one of UDP, + TCP, or TLS)) used to communicate between the client and the + server. The 5-tuple uniquely identifies this communication + stream. The 5-tuple also uniquely identifies the Allocation on + the server. + + Channel: A channel number and associated peer transport address. + Once a channel number is bound to a peer's transport address, the + client and server can use the more bandwidth-efficient ChannelData + message to exchange data. + + Permission: The IP address and transport protocol (but not the port) + of a peer that is permitted to send traffic to the TURN server and + have that traffic relayed to the TURN client. The TURN server + will only forward traffic to its client from peers that match an + existing permission. + + Realm: A string used to describe the server or a context within the + server. The realm tells the client which username and password + combination to use to authenticate requests. + + Nonce: A string chosen at random by the server and included in the + message-digest. To prevent reply attacks, the server should + change the nonce regularly. + +4. General Behavior + + This section contains general TURN processing rules that apply to all + TURN messages. + + TURN is an extension to STUN. All TURN messages, with the exception + of the ChannelData message, are STUN-formatted messages. All the + base processing rules described in [RFC5389] apply to STUN-formatted + messages. This means that all the message-forming and message- + processing descriptions in this document are implicitly prefixed with + the rules of [RFC5389]. + + [RFC5389] specifies an authentication mechanism called the long-term + credential mechanism. TURN servers and clients MUST implement this + mechanism. The server MUST demand that all requests from the client + be authenticated using this mechanism, or that a equally strong or + stronger mechanism for client authentication is used. + + + + +Mahy, et al. Standards Track [Page 19] + +RFC 5766 TURN April 2010 + + + Note that the long-term credential mechanism applies only to requests + and cannot be used to authenticate indications; thus, indications in + TURN are never authenticated. If the server requires requests to be + authenticated, then the server's administrator MUST choose a realm + value that will uniquely identify the username and password + combination that the client must use, even if the client uses + multiple servers under different administrations. The server's + administrator MAY choose to allocate a unique username to each + client, or MAY choose to allocate the same username to more than one + client (for example, to all clients from the same department or + company). For each allocation, the server SHOULD generate a new + random nonce when the allocation is first attempted following the + randomness recommendations in [RFC4086] and SHOULD expire the nonce + at least once every hour during the lifetime of the allocation. + + All requests after the initial Allocate must use the same username as + that used to create the allocation, to prevent attackers from + hijacking the client's allocation. Specifically, if the server + requires the use of the long-term credential mechanism, and if a non- + Allocate request passes authentication under this mechanism, and if + the 5-tuple identifies an existing allocation, but the request does + not use the same username as used to create the allocation, then the + request MUST be rejected with a 441 (Wrong Credentials) error. + + When a TURN message arrives at the server from the client, the server + uses the 5-tuple in the message to identify the associated + allocation. For all TURN messages (including ChannelData) EXCEPT an + Allocate request, if the 5-tuple does not identify an existing + allocation, then the message MUST either be rejected with a 437 + Allocation Mismatch error (if it is a request) or silently ignored + (if it is an indication or a ChannelData message). A client + receiving a 437 error response to a request other than Allocate MUST + assume the allocation no longer exists. + + [RFC5389] defines a number of attributes, including the SOFTWARE and + FINGERPRINT attributes. The client SHOULD include the SOFTWARE + attribute in all Allocate and Refresh requests and MAY include it in + any other requests or indications. The server SHOULD include the + SOFTWARE attribute in all Allocate and Refresh responses (either + success or failure) and MAY include it in other responses or + indications. The client and the server MAY include the FINGERPRINT + attribute in any STUN-formatted messages defined in this document. + + TURN does not use the backwards-compatibility mechanism described in + [RFC5389]. + + + + + + +Mahy, et al. Standards Track [Page 20] + +RFC 5766 TURN April 2010 + + + TURN, as defined in this specification, only supports IPv4. The + client's IP address, the server's IP address, and all IP addresses + appearing in a relayed transport address MUST be IPv4 addresses. + + By default, TURN runs on the same ports as STUN: 3478 for TURN over + UDP and TCP, and 5349 for TURN over TLS. However, TURN has its own + set of Service Record (SRV) names: "turn" for UDP and TCP, and + "turns" for TLS. Either the SRV procedures or the ALTERNATE-SERVER + procedures, both described in Section 6, can be used to run TURN on a + different port. + + To ensure interoperability, a TURN server MUST support the use of UDP + transport between the client and the server, and SHOULD support the + use of TCP and TLS transport. + + When UDP transport is used between the client and the server, the + client will retransmit a request if it does not receive a response + within a certain timeout period. Because of this, the server may + receive two (or more) requests with the same 5-tuple and same + transaction id. STUN requires that the server recognize this case + and treat the request as idempotent (see [RFC5389]). Some + implementations may choose to meet this requirement by remembering + all received requests and the corresponding responses for 40 seconds. + Other implementations may choose to reprocess the request and arrange + that such reprocessing returns essentially the same response. To aid + implementors who choose the latter approach (the so-called "stateless + stack approach"), this specification includes some implementation + notes on how this might be done. Implementations are free to choose + either approach or choose some other approach that gives the same + results. + + When TCP transport is used between the client and the server, it is + possible that a bit error will cause a length field in a TURN packet + to become corrupted, causing the receiver to lose synchronization + with the incoming stream of TURN messages. A client or server that + detects a long sequence of invalid TURN messages over TCP transport + SHOULD close the corresponding TCP connection to help the other end + detect this situation more rapidly. + + To mitigate either intentional or unintentional denial-of-service + attacks against the server by clients with valid usernames and + passwords, it is RECOMMENDED that the server impose limits on both + the number of allocations active at one time for a given username and + on the amount of bandwidth those allocations can use. The server + should reject new allocations that would exceed the limit on the + allowed number of allocations active at one time with a 486 + (Allocation Quota Exceeded) (see Section 6.2), and should discard + application data traffic that exceeds the bandwidth quota. + + + +Mahy, et al. Standards Track [Page 21] + +RFC 5766 TURN April 2010 + + +5. Allocations + + All TURN operations revolve around allocations, and all TURN messages + are associated with an allocation. An allocation conceptually + consists of the following state data: + + o the relayed transport address; + + o the 5-tuple: (client's IP address, client's port, server IP + address, server port, transport protocol); + + o the authentication information; + + o the time-to-expiry; + + o a list of permissions; + + o a list of channel to peer bindings. + + The relayed transport address is the transport address allocated by + the server for communicating with peers, while the 5-tuple describes + the communication path between the client and the server. On the + client, the 5-tuple uses the client's host transport address; on the + server, the 5-tuple uses the client's server-reflexive transport + address. + + Both the relayed transport address and the 5-tuple MUST be unique + across all allocations, so either one can be used to uniquely + identify the allocation. + + The authentication information (e.g., username, password, realm, and + nonce) is used to both verify subsequent requests and to compute the + message integrity of responses. The username, realm, and nonce + values are initially those used in the authenticated Allocate request + that creates the allocation, though the server can change the nonce + value during the lifetime of the allocation using a 438 (Stale Nonce) + reply. Note that, rather than storing the password explicitly, for + security reasons, it may be desirable for the server to store the key + value, which is an MD5 hash over the username, realm, and password + (see [RFC5389]). + + The time-to-expiry is the time in seconds left until the allocation + expires. Each Allocate or Refresh transaction sets this timer, which + then ticks down towards 0. By default, each Allocate or Refresh + transaction resets this timer to the default lifetime value of 600 + seconds (10 minutes), but the client can request a different value in + the Allocate and Refresh request. Allocations can only be refreshed + using the Refresh request; sending data to a peer does not refresh an + + + +Mahy, et al. Standards Track [Page 22] + +RFC 5766 TURN April 2010 + + + allocation. When an allocation expires, the state data associated + with the allocation can be freed. + + The list of permissions is described in Section 8 and the list of + channels is described in Section 11. + +6. Creating an Allocation + + An allocation on the server is created using an Allocate transaction. + +6.1. Sending an Allocate Request + + The client forms an Allocate request as follows. + + The client first picks a host transport address. It is RECOMMENDED + that the client pick a currently unused transport address, typically + by allowing the underlying OS to pick a currently unused port for a + new socket. + + The client then picks a transport protocol to use between the client + and the server. The transport protocol MUST be one of UDP, TCP, or + TLS-over-TCP. Since this specification only allows UDP between the + server and the peers, it is RECOMMENDED that the client pick UDP + unless it has a reason to use a different transport. One reason to + pick a different transport would be that the client believes, either + through configuration or by experiment, that it is unable to contact + any TURN server using UDP. See Section 2.1 for more discussion. + + The client also picks a server transport address, which SHOULD be + done as follows. The client receives (perhaps through configuration) + a domain name for a TURN server. The client then uses the DNS + procedures described in [RFC5389], but using an SRV service name of + "turn" (or "turns" for TURN over TLS) instead of "stun" (or "stuns"). + For example, to find servers in the example.com domain, the client + performs a lookup for '_turn._udp.example.com', + '_turn._tcp.example.com', and '_turns._tcp.example.com' if the client + wants to communicate with the server using UDP, TCP, or TLS-over-TCP, + respectively. + + The client MUST include a REQUESTED-TRANSPORT attribute in the + request. This attribute specifies the transport protocol between the + server and the peers (note that this is NOT the transport protocol + that appears in the 5-tuple). In this specification, the REQUESTED- + TRANSPORT type is always UDP. This attribute is included to allow + future extensions to specify other protocols. + + If the client wishes the server to initialize the time-to-expiry + field of the allocation to some value other than the default + + + +Mahy, et al. Standards Track [Page 23] + +RFC 5766 TURN April 2010 + + + lifetime, then it MAY include a LIFETIME attribute specifying its + desired value. This is just a request, and the server may elect to + use a different value. Note that the server will ignore requests to + initialize the field to less than the default value. + + If the client wishes to later use the DONT-FRAGMENT attribute in one + or more Send indications on this allocation, then the client SHOULD + include the DONT-FRAGMENT attribute in the Allocate request. This + allows the client to test whether this attribute is supported by the + server. + + If the client requires the port number of the relayed transport + address be even, the client includes the EVEN-PORT attribute. If + this attribute is not included, then the port can be even or odd. By + setting the R bit in the EVEN-PORT attribute to 1, the client can + request that the server reserve the next highest port number (on the + same IP address) for a subsequent allocation. If the R bit is 0, no + such request is made. + + The client MAY also include a RESERVATION-TOKEN attribute in the + request to ask the server to use a previously reserved port for the + allocation. If the RESERVATION-TOKEN attribute is included, then the + client MUST omit the EVEN-PORT attribute. + + Once constructed, the client sends the Allocate request on the + 5-tuple. + +6.2. Receiving an Allocate Request + + When the server receives an Allocate request, it performs the + following checks: + + 1. The server MUST require that the request be authenticated. This + authentication MUST be done using the long-term credential + mechanism of [RFC5389] unless the client and server agree to use + another mechanism through some procedure outside the scope of + this document. + + 2. The server checks if the 5-tuple is currently in use by an + existing allocation. If yes, the server rejects the request with + a 437 (Allocation Mismatch) error. + + 3. The server checks if the request contains a REQUESTED-TRANSPORT + attribute. If the REQUESTED-TRANSPORT attribute is not included + or is malformed, the server rejects the request with a 400 (Bad + Request) error. Otherwise, if the attribute is included but + specifies a protocol other that UDP, the server rejects the + request with a 442 (Unsupported Transport Protocol) error. + + + +Mahy, et al. Standards Track [Page 24] + +RFC 5766 TURN April 2010 + + + 4. The request may contain a DONT-FRAGMENT attribute. If it does, + but the server does not support sending UDP datagrams with the DF + bit set to 1 (see Section 12), then the server treats the DONT- + FRAGMENT attribute in the Allocate request as an unknown + comprehension-required attribute. + + 5. The server checks if the request contains a RESERVATION-TOKEN + attribute. If yes, and the request also contains an EVEN-PORT + attribute, then the server rejects the request with a 400 (Bad + Request) error. Otherwise, it checks to see if the token is + valid (i.e., the token is in range and has not expired and the + corresponding relayed transport address is still available). If + the token is not valid for some reason, the server rejects the + request with a 508 (Insufficient Capacity) error. + + 6. The server checks if the request contains an EVEN-PORT attribute. + If yes, then the server checks that it can satisfy the request + (i.e., can allocate a relayed transport address as described + below). If the server cannot satisfy the request, then the + server rejects the request with a 508 (Insufficient Capacity) + error. + + 7. At any point, the server MAY choose to reject the request with a + 486 (Allocation Quota Reached) error if it feels the client is + trying to exceed some locally defined allocation quota. The + server is free to define this allocation quota any way it wishes, + but SHOULD define it based on the username used to authenticate + the request, and not on the client's transport address. + + 8. Also at any point, the server MAY choose to reject the request + with a 300 (Try Alternate) error if it wishes to redirect the + client to a different server. The use of this error code and + attribute follow the specification in [RFC5389]. + + If all the checks pass, the server creates the allocation. The + 5-tuple is set to the 5-tuple from the Allocate request, while the + list of permissions and the list of channels are initially empty. + + The server chooses a relayed transport address for the allocation as + follows: + + o If the request contains a RESERVATION-TOKEN, the server uses the + previously reserved transport address corresponding to the + included token (if it is still available). Note that the + reservation is a server-wide reservation and is not specific to a + particular allocation, since the Allocate request containing the + RESERVATION-TOKEN uses a different 5-tuple than the Allocate + request that made the reservation. The 5-tuple for the Allocate + + + +Mahy, et al. Standards Track [Page 25] + +RFC 5766 TURN April 2010 + + + request containing the RESERVATION-TOKEN attribute can be any + allowed 5-tuple; it can use a different client IP address and + port, a different transport protocol, and even different server IP + address and port (provided, of course, that the server IP address + and port are ones on which the server is listening for TURN + requests). + + o If the request contains an EVEN-PORT attribute with the R bit set + to 0, then the server allocates a relayed transport address with + an even port number. + + o If the request contains an EVEN-PORT attribute with the R bit set + to 1, then the server looks for a pair of port numbers N and N+1 + on the same IP address, where N is even. Port N is used in the + current allocation, while the relayed transport address with port + N+1 is assigned a token and reserved for a future allocation. The + server MUST hold this reservation for at least 30 seconds, and MAY + choose to hold longer (e.g., until the allocation with port N + expires). The server then includes the token in a RESERVATION- + TOKEN attribute in the success response. + + o Otherwise, the server allocates any available relayed transport + address. + + In all cases, the server SHOULD only allocate ports from the range + 49152 - 65535 (the Dynamic and/or Private Port range [Port-Numbers]), + unless the TURN server application knows, through some means not + specified here, that other applications running on the same host as + the TURN server application will not be impacted by allocating ports + outside this range. This condition can often be satisfied by running + the TURN server application on a dedicated machine and/or by + arranging that any other applications on the machine allocate ports + before the TURN server application starts. In any case, the TURN + server SHOULD NOT allocate ports in the range 0 - 1023 (the Well- + Known Port range) to discourage clients from using TURN to run + standard services. + + NOTE: The IETF is currently investigating the topic of randomized + port assignments to avoid certain types of attacks (see + [TSVWG-PORT]). It is strongly recommended that a TURN implementor + keep abreast of this topic and, if appropriate, implement a + randomized port assignment algorithm. This is especially + applicable to servers that choose to pre-allocate a number of + ports from the underlying OS and then later assign them to + allocations; for example, a server may choose this technique to + implement the EVEN-PORT attribute. + + + + + +Mahy, et al. Standards Track [Page 26] + +RFC 5766 TURN April 2010 + + + The server determines the initial value of the time-to-expiry field + as follows. If the request contains a LIFETIME attribute, then the + server computes the minimum of the client's proposed lifetime and the + server's maximum allowed lifetime. If this computed value is greater + than the default lifetime, then the server uses the computed lifetime + as the initial value of the time-to-expiry field. Otherwise, the + server uses the default lifetime. It is RECOMMENDED that the server + use a maximum allowed lifetime value of no more than 3600 seconds (1 + hour). Servers that implement allocation quotas or charge users for + allocations in some way may wish to use a smaller maximum allowed + lifetime (perhaps as small as the default lifetime) to more quickly + remove orphaned allocations (that is, allocations where the + corresponding client has crashed or terminated or the client + connection has been lost for some reason). Also, note that the time- + to-expiry is recomputed with each successful Refresh request, and + thus the value computed here applies only until the first refresh. + + Once the allocation is created, the server replies with a success + response. The success response contains: + + o An XOR-RELAYED-ADDRESS attribute containing the relayed transport + address. + + o A LIFETIME attribute containing the current value of the time-to- + expiry timer. + + o A RESERVATION-TOKEN attribute (if a second relayed transport + address was reserved). + + o An XOR-MAPPED-ADDRESS attribute containing the client's IP address + and port (from the 5-tuple). + + NOTE: The XOR-MAPPED-ADDRESS attribute is included in the response + as a convenience to the client. TURN itself does not make use of + this value, but clients running ICE can often need this value and + can thus avoid having to do an extra Binding transaction with some + STUN server to learn it. + + The response (either success or error) is sent back to the client on + the 5-tuple. + + NOTE: When the Allocate request is sent over UDP, section 7.3.1 of + [RFC5389] requires that the server handle the possible + retransmissions of the request so that retransmissions do not + cause multiple allocations to be created. Implementations may + achieve this using the so-called "stateless stack approach" as + follows. To detect retransmissions when the original request was + successful in creating an allocation, the server can store the + + + +Mahy, et al. Standards Track [Page 27] + +RFC 5766 TURN April 2010 + + + transaction id that created the request with the allocation data + and compare it with incoming Allocate requests on the same + 5-tuple. Once such a request is detected, the server can stop + parsing the request and immediately generate a success response. + When building this response, the value of the LIFETIME attribute + can be taken from the time-to-expiry field in the allocate state + data, even though this value may differ slightly from the LIFETIME + value originally returned. In addition, the server may need to + store an indication of any reservation token returned in the + original response, so that this may be returned in any + retransmitted responses. + + For the case where the original request was unsuccessful in + creating an allocation, the server may choose to do nothing + special. Note, however, that there is a rare case where the + server rejects the original request but accepts the retransmitted + request (because conditions have changed in the brief intervening + time period). If the client receives the first failure response, + it will ignore the second (success) response and believe that an + allocation was not created. An allocation created in this matter + will eventually timeout, since the client will not refresh it. + Furthermore, if the client later retries with the same 5-tuple but + different transaction id, it will receive a 437 (Allocation + Mismatch), which will cause it to retry with a different 5-tuple. + The server may use a smaller maximum lifetime value to minimize + the lifetime of allocations "orphaned" in this manner. + +6.3. Receiving an Allocate Success Response + + If the client receives an Allocate success response, then it MUST + check that the mapped address and the relayed transport address are + in an address family that the client understands and is prepared to + handle. This specification only covers the case where these two + addresses are IPv4 addresses. If these two addresses are not in an + address family which the client is prepared to handle, then the + client MUST delete the allocation (Section 7) and MUST NOT attempt to + create another allocation on that server until it believes the + mismatch has been fixed. + + The IETF is currently considering mechanisms for transitioning + between IPv4 and IPv6 that could result in a client originating an + Allocate request over IPv6, but the request would arrive at the + server over IPv4, or vice versa. + + Otherwise, the client creates its own copy of the allocation data + structure to track what is happening on the server. In particular, + the client needs to remember the actual lifetime received back from + the server, rather than the value sent to the server in the request. + + + +Mahy, et al. Standards Track [Page 28] + +RFC 5766 TURN April 2010 + + + The client must also remember the 5-tuple used for the request and + the username and password it used to authenticate the request to + ensure that it reuses them for subsequent messages. The client also + needs to track the channels and permissions it establishes on the + server. + + The client will probably wish to send the relayed transport address + to peers (using some method not specified here) so the peers can + communicate with it. The client may also wish to use the server- + reflexive address it receives in the XOR-MAPPED-ADDRESS attribute in + its ICE processing. + +6.4. Receiving an Allocate Error Response + + If the client receives an Allocate error response, then the + processing depends on the actual error code returned: + + o (Request timed out): There is either a problem with the server, or + a problem reaching the server with the chosen transport. The + client considers the current transaction as having failed but MAY + choose to retry the Allocate request using a different transport + (e.g., TCP instead of UDP). + + o 300 (Try Alternate): The server would like the client to use the + server specified in the ALTERNATE-SERVER attribute instead. The + client considers the current transaction as having failed, but + SHOULD try the Allocate request with the alternate server before + trying any other servers (e.g., other servers discovered using the + SRV procedures). When trying the Allocate request with the + alternate server, the client follows the ALTERNATE-SERVER + procedures specified in [RFC5389]. + + o 400 (Bad Request): The server believes the client's request is + malformed for some reason. The client considers the current + transaction as having failed. The client MAY notify the user or + operator and SHOULD NOT retry the request with this server until + it believes the problem has been fixed. + + o 401 (Unauthorized): If the client has followed the procedures of + the long-term credential mechanism and still gets this error, then + the server is not accepting the client's credentials. In this + case, the client considers the current transaction as having + failed and SHOULD notify the user or operator. The client SHOULD + NOT send any further requests to this server until it believes the + problem has been fixed. + + + + + + +Mahy, et al. Standards Track [Page 29] + +RFC 5766 TURN April 2010 + + + o 403 (Forbidden): The request is valid, but the server is refusing + to perform it, likely due to administrative restrictions. The + client considers the current transaction as having failed. The + client MAY notify the user or operator and SHOULD NOT retry the + same request with this server until it believes the problem has + been fixed. + + o 420 (Unknown Attribute): If the client included a DONT-FRAGMENT + attribute in the request and the server rejected the request with + a 420 error code and listed the DONT-FRAGMENT attribute in the + UNKNOWN-ATTRIBUTES attribute in the error response, then the + client now knows that the server does not support the DONT- + FRAGMENT attribute. The client considers the current transaction + as having failed but MAY choose to retry the Allocate request + without the DONT-FRAGMENT attribute. + + o 437 (Allocation Mismatch): This indicates that the client has + picked a 5-tuple that the server sees as already in use. One way + this could happen is if an intervening NAT assigned a mapped + transport address that was used by another client that recently + crashed. The client considers the current transaction as having + failed. The client SHOULD pick another client transport address + and retry the Allocate request (using a different transaction id). + The client SHOULD try three different client transport addresses + before giving up on this server. Once the client gives up on the + server, it SHOULD NOT try to create another allocation on the + server for 2 minutes. + + o 438 (Stale Nonce): See the procedures for the long-term credential + mechanism [RFC5389]. + + o 441 (Wrong Credentials): The client should not receive this error + in response to a Allocate request. The client MAY notify the user + or operator and SHOULD NOT retry the same request with this server + until it believes the problem has been fixed. + + o 442 (Unsupported Transport Address): The client should not receive + this error in response to a request for a UDP allocation. The + client MAY notify the user or operator and SHOULD NOT reattempt + the request with this server until it believes the problem has + been fixed. + + o 486 (Allocation Quota Reached): The server is currently unable to + create any more allocations with this username. The client + considers the current transaction as having failed. The client + SHOULD wait at least 1 minute before trying to create any more + allocations on the server. + + + + +Mahy, et al. Standards Track [Page 30] + +RFC 5766 TURN April 2010 + + + o 508 (Insufficient Capacity): The server has no more relayed + transport addresses available, or has none with the requested + properties, or the one that was reserved is no longer available. + The client considers the current operation as having failed. If + the client is using either the EVEN-PORT or the RESERVATION-TOKEN + attribute, then the client MAY choose to remove or modify this + attribute and try again immediately. Otherwise, the client SHOULD + wait at least 1 minute before trying to create any more + allocations on this server. + + An unknown error response MUST be handled as described in [RFC5389]. + +7. Refreshing an Allocation + + A Refresh transaction can be used to either (a) refresh an existing + allocation and update its time-to-expiry or (b) delete an existing + allocation. + + If a client wishes to continue using an allocation, then the client + MUST refresh it before it expires. It is suggested that the client + refresh the allocation roughly 1 minute before it expires. If a + client no longer wishes to use an allocation, then it SHOULD + explicitly delete the allocation. A client MAY refresh an allocation + at any time for other reasons. + +7.1. Sending a Refresh Request + + If the client wishes to immediately delete an existing allocation, it + includes a LIFETIME attribute with a value of 0. All other forms of + the request refresh the allocation. + + The Refresh transaction updates the time-to-expiry timer of an + allocation. If the client wishes the server to set the time-to- + expiry timer to something other than the default lifetime, it + includes a LIFETIME attribute with the requested value. The server + then computes a new time-to-expiry value in the same way as it does + for an Allocate transaction, with the exception that a requested + lifetime of 0 causes the server to immediately delete the allocation. + +7.2. Receiving a Refresh Request + + When the server receives a Refresh request, it processes as per + Section 4 plus the specific rules mentioned here. + + The server computes a value called the "desired lifetime" as follows: + if the request contains a LIFETIME attribute and the attribute value + is 0, then the "desired lifetime" is 0. Otherwise, if the request + contains a LIFETIME attribute, then the server computes the minimum + + + +Mahy, et al. Standards Track [Page 31] + +RFC 5766 TURN April 2010 + + + of the client's requested lifetime and the server's maximum allowed + lifetime. If this computed value is greater than the default + lifetime, then the "desired lifetime" is the computed value. + Otherwise, the "desired lifetime" is the default lifetime. + + Subsequent processing depends on the "desired lifetime" value: + + o If the "desired lifetime" is 0, then the request succeeds and the + allocation is deleted. + + o If the "desired lifetime" is non-zero, then the request succeeds + and the allocation's time-to-expiry is set to the "desired + lifetime". + + If the request succeeds, then the server sends a success response + containing: + + o A LIFETIME attribute containing the current value of the time-to- + expiry timer. + + NOTE: A server need not do anything special to implement + idempotency of Refresh requests over UDP using the "stateless + stack approach". Retransmitted Refresh requests with a non-zero + "desired lifetime" will simply refresh the allocation. A + retransmitted Refresh request with a zero "desired lifetime" will + cause a 437 (Allocation Mismatch) response if the allocation has + already been deleted, but the client will treat this as equivalent + to a success response (see below). + +7.3. Receiving a Refresh Response + + If the client receives a success response to its Refresh request with + a non-zero lifetime, it updates its copy of the allocation data + structure with the time-to-expiry value contained in the response. + + If the client receives a 437 (Allocation Mismatch) error response to + a request to delete the allocation, then the allocation no longer + exists and it should consider its request as having effectively + succeeded. + +8. Permissions + + For each allocation, the server keeps a list of zero or more + permissions. Each permission consists of an IP address and an + associated time-to-expiry. While a permission exists, all peers + using the IP address in the permission are allowed to send data to + + + + + +Mahy, et al. Standards Track [Page 32] + +RFC 5766 TURN April 2010 + + + the client. The time-to-expiry is the number of seconds until the + permission expires. Within the context of an allocation, a + permission is uniquely identified by its associated IP address. + + By sending either CreatePermission requests or ChannelBind requests, + the client can cause the server to install or refresh a permission + for a given IP address. This causes one of two things to happen: + + o If no permission for that IP address exists, then a permission is + created with the given IP address and a time-to-expiry equal to + Permission Lifetime. + + o If a permission for that IP address already exists, then the time- + to-expiry for that permission is reset to Permission Lifetime. + + The Permission Lifetime MUST be 300 seconds (= 5 minutes). + + Each permission's time-to-expiry decreases down once per second until + it reaches 0; at which point, the permission expires and is deleted. + + CreatePermission and ChannelBind requests may be freely intermixed on + a permission. A given permission may be initially installed and/or + refreshed with a CreatePermission request, and then later refreshed + with a ChannelBind request, or vice versa. + + When a UDP datagram arrives at the relayed transport address for the + allocation, the server extracts the source IP address from the IP + header. The server then compares this address with the IP address + associated with each permission in the list of permissions for the + allocation. If no match is found, relaying is not permitted, and the + server silently discards the UDP datagram. If an exact match is + found, then the permission check is considered to have succeeded and + the server continues to process the UDP datagram as specified + elsewhere (Section 10.3). Note that only addresses are compared and + port numbers are not considered. + + The permissions for one allocation are totally unrelated to the + permissions for a different allocation. If an allocation expires, + all its permissions expire with it. + + NOTE: Though TURN permissions expire after 5 minutes, many NATs + deployed at the time of publication expire their UDP bindings + considerably faster. Thus, an application using TURN will + probably wish to send some sort of keep-alive traffic at a much + faster rate. Applications using ICE should follow the keep-alive + guidelines of ICE [RFC5245], and applications not using ICE are + advised to do something similar. + + + + +Mahy, et al. Standards Track [Page 33] + +RFC 5766 TURN April 2010 + + +9. CreatePermission + + TURN supports two ways for the client to install or refresh + permissions on the server. This section describes one way: the + CreatePermission request. + + A CreatePermission request may be used in conjunction with either the + Send mechanism in Section 10 or the Channel mechanism in Section 11. + +9.1. Forming a CreatePermission Request + + The client who wishes to install or refresh one or more permissions + can send a CreatePermission request to the server. + + When forming a CreatePermission request, the client MUST include at + least one XOR-PEER-ADDRESS attribute, and MAY include more than one + such attribute. The IP address portion of each XOR-PEER-ADDRESS + attribute contains the IP address for which a permission should be + installed or refreshed. The port portion of each XOR-PEER-ADDRESS + attribute will be ignored and can be any arbitrary value. The + various XOR-PEER-ADDRESS attributes can appear in any order. + +9.2. Receiving a CreatePermission Request + + When the server receives the CreatePermission request, it processes + as per Section 4 plus the specific rules mentioned here. + + The message is checked for validity. The CreatePermission request + MUST contain at least one XOR-PEER-ADDRESS attribute and MAY contain + multiple such attributes. If no such attribute exists, or if any of + these attributes are invalid, then a 400 (Bad Request) error is + returned. If the request is valid, but the server is unable to + satisfy the request due to some capacity limit or similar, then a 508 + (Insufficient Capacity) error is returned. + + The server MAY impose restrictions on the IP address allowed in the + XOR-PEER-ADDRESS attribute -- if a value is not allowed, the server + rejects the request with a 403 (Forbidden) error. + + If the message is valid and the server is capable of carrying out the + request, then the server installs or refreshes a permission for the + IP address contained in each XOR-PEER-ADDRESS attribute as described + in Section 8. The port portion of each attribute is ignored and may + be any arbitrary value. + + The server then responds with a CreatePermission success response. + There are no mandatory attributes in the success response. + + + + +Mahy, et al. Standards Track [Page 34] + +RFC 5766 TURN April 2010 + + + NOTE: A server need not do anything special to implement + idempotency of CreatePermission requests over UDP using the + "stateless stack approach". Retransmitted CreatePermission + requests will simply refresh the permissions. + +9.3. Receiving a CreatePermission Response + + If the client receives a valid CreatePermission success response, + then the client updates its data structures to indicate that the + permissions have been installed or refreshed. + +10. Send and Data Methods + + TURN supports two mechanisms for sending and receiving data from + peers. This section describes the use of the Send and Data + mechanisms, while Section 11 describes the use of the Channel + mechanism. + +10.1. Forming a Send Indication + + The client can use a Send indication to pass data to the server for + relaying to a peer. A client may use a Send indication even if a + channel is bound to that peer. However, the client MUST ensure that + there is a permission installed for the IP address of the peer to + which the Send indication is being sent; this prevents a third party + from using a TURN server to send data to arbitrary destinations. + + When forming a Send indication, the client MUST include an XOR-PEER- + ADDRESS attribute and a DATA attribute. The XOR-PEER-ADDRESS + attribute contains the transport address of the peer to which the + data is to be sent, and the DATA attribute contains the actual + application data to be sent to the peer. + + The client MAY include a DONT-FRAGMENT attribute in the Send + indication if it wishes the server to set the DF bit on the UDP + datagram sent to the peer. + +10.2. Receiving a Send Indication + + When the server receives a Send indication, it processes as per + Section 4 plus the specific rules mentioned here. + + The message is first checked for validity. The Send indication MUST + contain both an XOR-PEER-ADDRESS attribute and a DATA attribute. If + one of these attributes is missing or invalid, then the message is + discarded. Note that the DATA attribute is allowed to contain zero + bytes of data. + + + + +Mahy, et al. Standards Track [Page 35] + +RFC 5766 TURN April 2010 + + + The Send indication may also contain the DONT-FRAGMENT attribute. If + the server is unable to set the DF bit on outgoing UDP datagrams when + this attribute is present, then the server acts as if the DONT- + FRAGMENT attribute is an unknown comprehension-required attribute + (and thus the Send indication is discarded). + + The server also checks that there is a permission installed for the + IP address contained in the XOR-PEER-ADDRESS attribute. If no such + permission exists, the message is discarded. Note that a Send + indication never causes the server to refresh the permission. + + The server MAY impose restrictions on the IP address and port values + allowed in the XOR-PEER-ADDRESS attribute -- if a value is not + allowed, the server silently discards the Send indication. + + If everything is OK, then the server forms a UDP datagram as follows: + + o the source transport address is the relayed transport address of + the allocation, where the allocation is determined by the 5-tuple + on which the Send indication arrived; + + o the destination transport address is taken from the XOR-PEER- + ADDRESS attribute; + + o the data following the UDP header is the contents of the value + field of the DATA attribute. + + The handling of the DONT-FRAGMENT attribute (if present), is + described in Section 12. + + The resulting UDP datagram is then sent to the peer. + +10.3. Receiving a UDP Datagram + + When the server receives a UDP datagram at a currently allocated + relayed transport address, the server looks up the allocation + associated with the relayed transport address. The server then + checks to see whether the set of permissions for the allocation allow + the relaying of the UDP datagram as described in Section 8. + + If relaying is permitted, then the server checks if there is a + channel bound to the peer that sent the UDP datagram (see + Section 11). If a channel is bound, then processing proceeds as + described in Section 11.7. + + If relaying is permitted but no channel is bound to the peer, then + the server forms and sends a Data indication. The Data indication + MUST contain both an XOR-PEER-ADDRESS and a DATA attribute. The DATA + + + +Mahy, et al. Standards Track [Page 36] + +RFC 5766 TURN April 2010 + + + attribute is set to the value of the 'data octets' field from the + datagram, and the XOR-PEER-ADDRESS attribute is set to the source + transport address of the received UDP datagram. The Data indication + is then sent on the 5-tuple associated with the allocation. + +10.4. Receiving a Data Indication + + When the client receives a Data indication, it checks that the Data + indication contains both an XOR-PEER-ADDRESS and a DATA attribute, + and discards the indication if it does not. The client SHOULD also + check that the XOR-PEER-ADDRESS attribute value contains an IP + address with which the client believes there is an active permission, + and discard the Data indication otherwise. Note that the DATA + attribute is allowed to contain zero bytes of data. + + NOTE: The latter check protects the client against an attacker who + somehow manages to trick the server into installing permissions + not desired by the client. + + If the Data indication passes the above checks, the client delivers + the data octets inside the DATA attribute to the application, along + with an indication that they were received from the peer whose + transport address is given by the XOR-PEER-ADDRESS attribute. + +11. Channels + + Channels provide a way for the client and server to send application + data using ChannelData messages, which have less overhead than Send + and Data indications. + + The ChannelData message (see Section 11.4) starts with a two-byte + field that carries the channel number. The values of this field are + allocated as follows: + + 0x0000 through 0x3FFF: These values can never be used for channel + numbers. + + 0x4000 through 0x7FFF: These values are the allowed channel + numbers (16,383 possible values). + + 0x8000 through 0xFFFF: These values are reserved for future use. + + Because of this division, ChannelData messages can be distinguished + from STUN-formatted messages (e.g., Allocate request, Send + indication, etc.) by examining the first two bits of the message: + + 0b00: STUN-formatted message (since the first two bits of a STUN- + formatted message are always zero). + + + +Mahy, et al. Standards Track [Page 37] + +RFC 5766 TURN April 2010 + + + 0b01: ChannelData message (since the channel number is the first + field in the ChannelData message and channel numbers fall in the + range 0x4000 - 0x7FFF). + + 0b10: Reserved + + 0b11: Reserved + + The reserved values may be used in the future to extend the range of + channel numbers. Thus, an implementation MUST NOT assume that a TURN + message always starts with a 0 bit. + + Channel bindings are always initiated by the client. The client can + bind a channel to a peer at any time during the lifetime of the + allocation. The client may bind a channel to a peer before + exchanging data with it, or after exchanging data with it (using Send + and Data indications) for some time, or may choose never to bind a + channel to it. The client can also bind channels to some peers while + not binding channels to other peers. + + Channel bindings are specific to an allocation, so that the use of a + channel number or peer transport address in a channel binding in one + allocation has no impact on their use in a different allocation. If + an allocation expires, all its channel bindings expire with it. + + A channel binding consists of: + + o a channel number; + + o a transport address (of the peer); and + + o A time-to-expiry timer. + + Within the context of an allocation, a channel binding is uniquely + identified either by the channel number or by the peer's transport + address. Thus, the same channel cannot be bound to two different + transport addresses, nor can the same transport address be bound to + two different channels. + + A channel binding lasts for 10 minutes unless refreshed. Refreshing + the binding (by the server receiving a ChannelBind request rebinding + the channel to the same peer) resets the time-to-expiry timer back to + 10 minutes. + + When the channel binding expires, the channel becomes unbound. Once + unbound, the channel number can be bound to a different transport + address, and the transport address can be bound to a different + channel number. To prevent race conditions, the client MUST wait 5 + + + +Mahy, et al. Standards Track [Page 38] + +RFC 5766 TURN April 2010 + + + minutes after the channel binding expires before attempting to bind + the channel number to a different transport address or the transport + address to a different channel number. + + When binding a channel to a peer, the client SHOULD be prepared to + receive ChannelData messages on the channel from the server as soon + as it has sent the ChannelBind request. Over UDP, it is possible for + the client to receive ChannelData messages from the server before it + receives a ChannelBind success response. + + In the other direction, the client MAY elect to send ChannelData + messages before receiving the ChannelBind success response. Doing + so, however, runs the risk of having the ChannelData messages dropped + by the server if the ChannelBind request does not succeed for some + reason (e.g., packet lost if the request is sent over UDP, or the + server being unable to fulfill the request). A client that wishes to + be safe should either queue the data or use Send indications until + the channel binding is confirmed. + +11.1. Sending a ChannelBind Request + + A channel binding is created or refreshed using a ChannelBind + transaction. A ChannelBind transaction also creates or refreshes a + permission towards the peer (see Section 8). + + To initiate the ChannelBind transaction, the client forms a + ChannelBind request. The channel to be bound is specified in a + CHANNEL-NUMBER attribute, and the peer's transport address is + specified in an XOR-PEER-ADDRESS attribute. Section 11.2 describes + the restrictions on these attributes. + + Rebinding a channel to the same transport address that it is already + bound to provides a way to refresh a channel binding and the + corresponding permission without sending data to the peer. Note + however, that permissions need to be refreshed more frequently than + channels. + +11.2. Receiving a ChannelBind Request + + When the server receives a ChannelBind request, it processes as per + Section 4 plus the specific rules mentioned here. + + The server checks the following: + + o The request contains both a CHANNEL-NUMBER and an XOR-PEER-ADDRESS + attribute; + + + + + +Mahy, et al. Standards Track [Page 39] + +RFC 5766 TURN April 2010 + + + o The channel number is in the range 0x4000 through 0x7FFE + (inclusive); + + o The channel number is not currently bound to a different transport + address (same transport address is OK); + + o The transport address is not currently bound to a different + channel number. + + If any of these tests fail, the server replies with a 400 (Bad + Request) error. + + The server MAY impose restrictions on the IP address and port values + allowed in the XOR-PEER-ADDRESS attribute -- if a value is not + allowed, the server rejects the request with a 403 (Forbidden) error. + + If the request is valid, but the server is unable to fulfill the + request due to some capacity limit or similar, the server replies + with a 508 (Insufficient Capacity) error. + + Otherwise, the server replies with a ChannelBind success response. + There are no required attributes in a successful ChannelBind + response. + + If the server can satisfy the request, then the server creates or + refreshes the channel binding using the channel number in the + CHANNEL-NUMBER attribute and the transport address in the XOR-PEER- + ADDRESS attribute. The server also installs or refreshes a + permission for the IP address in the XOR-PEER-ADDRESS attribute as + described in Section 8. + + NOTE: A server need not do anything special to implement + idempotency of ChannelBind requests over UDP using the "stateless + stack approach". Retransmitted ChannelBind requests will simply + refresh the channel binding and the corresponding permission. + Furthermore, the client must wait 5 minutes before binding a + previously bound channel number or peer address to a different + channel, eliminating the possibility that the transaction would + initially fail but succeed on a retransmission. + +11.3. Receiving a ChannelBind Response + + When the client receives a ChannelBind success response, it updates + its data structures to record that the channel binding is now active. + It also updates its data structures to record that the corresponding + permission has been installed or refreshed. + + + + + +Mahy, et al. Standards Track [Page 40] + +RFC 5766 TURN April 2010 + + + If the client receives a ChannelBind failure response that indicates + that the channel information is out-of-sync between the client and + the server (e.g., an unexpected 400 "Bad Request" response), then it + is RECOMMENDED that the client immediately delete the allocation and + start afresh with a new allocation. + +11.4. The ChannelData Message + + The ChannelData message is used to carry application data between the + client and the server. It has the following format: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Channel Number | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + / Application Data / + / / + | | + | +-------------------------------+ + | | + +-------------------------------+ + + The Channel Number field specifies the number of the channel on which + the data is traveling, and thus the address of the peer that is + sending or is to receive the data. + + The Length field specifies the length in bytes of the application + data field (i.e., it does not include the size of the ChannelData + header). Note that 0 is a valid length. + + The Application Data field carries the data the client is trying to + send to the peer, or that the peer is sending to the client. + +11.5. Sending a ChannelData Message + + Once a client has bound a channel to a peer, then when the client has + data to send to that peer it may use either a ChannelData message or + a Send indication; that is, the client is not obligated to use the + channel when it exists and may freely intermix the two message types + when sending data to the peer. The server, on the other hand, MUST + use the ChannelData message if a channel has been bound to the peer. + + The fields of the ChannelData message are filled in as described in + Section 11.4. + + + + + +Mahy, et al. Standards Track [Page 41] + +RFC 5766 TURN April 2010 + + + Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to + a multiple of four bytes in order to ensure the alignment of + subsequent messages. The padding is not reflected in the length + field of the ChannelData message, so the actual size of a ChannelData + message (including padding) is (4 + Length) rounded up to the nearest + multiple of 4. Over UDP, the padding is not required but MAY be + included. + + The ChannelData message is then sent on the 5-tuple associated with + the allocation. + +11.6. Receiving a ChannelData Message + + The receiver of the ChannelData message uses the first two bits to + distinguish it from STUN-formatted messages, as described above. If + the message uses a value in the reserved range (0x8000 through + 0xFFFF), then the message is silently discarded. + + If the ChannelData message is received in a UDP datagram, and if the + UDP datagram is too short to contain the claimed length of the + ChannelData message (i.e., the UDP header length field value is less + than the ChannelData header length field value + 4 + 8), then the + message is silently discarded. + + If the ChannelData message is received over TCP or over TLS-over-TCP, + then the actual length of the ChannelData message is as described in + Section 11.5. + + If the ChannelData message is received on a channel that is not bound + to any peer, then the message is silently discarded. + + On the client, it is RECOMMENDED that the client discard the + ChannelData message if the client believes there is no active + permission towards the peer. On the server, the receipt of a + ChannelData message MUST NOT refresh either the channel binding or + the permission towards the peer. + + On the server, if no errors are detected, the server relays the + application data to the peer by forming a UDP datagram as follows: + + o the source transport address is the relayed transport address of + the allocation, where the allocation is determined by the 5-tuple + on which the ChannelData message arrived; + + o the destination transport address is the transport address to + which the channel is bound; + + + + + +Mahy, et al. Standards Track [Page 42] + +RFC 5766 TURN April 2010 + + + o the data following the UDP header is the contents of the data + field of the ChannelData message. + + The resulting UDP datagram is then sent to the peer. Note that if + the Length field in the ChannelData message is 0, then there will be + no data in the UDP datagram, but the UDP datagram is still formed and + sent. + +11.7. Relaying Data from the Peer + + When the server receives a UDP datagram on the relayed transport + address associated with an allocation, the server processes it as + described in Section 10.3. If that section indicates that a + ChannelData message should be sent (because there is a channel bound + to the peer that sent to the UDP datagram), then the server forms and + sends a ChannelData message as described in Section 11.5. + +12. IP Header Fields + + This section describes how the server sets various fields in the IP + header when relaying between the client and the peer or vice versa. + The descriptions in this section apply: (a) when the server sends a + UDP datagram to the peer, or (b) when the server sends a Data + indication or ChannelData message to the client over UDP transport. + The descriptions in this section do not apply to TURN messages sent + over TCP or TLS transport from the server to the client. + + The descriptions below have two parts: a preferred behavior and an + alternate behavior. The server SHOULD implement the preferred + behavior, but if that is not possible for a particular field, then it + SHOULD implement the alternative behavior. + + Time to Live (TTL) field + + Preferred Behavior: If the incoming value is 0, then the drop the + incoming packet. Otherwise, set the outgoing Time to Live/Hop + Count to one less than the incoming value. + + Alternate Behavior: Set the outgoing value to the default for + outgoing packets. + + Differentiated Services Code Point (DSCP) field [RFC2474] + + Preferred Behavior: Set the outgoing value to the incoming value, + unless the server includes a differentiated services classifier + and marker [RFC2474]. + + + + + +Mahy, et al. Standards Track [Page 43] + +RFC 5766 TURN April 2010 + + + Alternate Behavior: Set the outgoing value to a fixed value, which + by default is Best Effort unless configured otherwise. + + In both cases, if the server is immediately adjacent to a + differentiated services classifier and marker, then DSCP MAY be + set to any arbitrary value in the direction towards the + classifier. + + Explicit Congestion Notification (ECN) field [RFC3168] + + Preferred Behavior: Set the outgoing value to the incoming value, + UNLESS the server is doing Active Queue Management, the incoming + ECN field is ECT(1) (=0b01) or ECT(0) (=0b10), and the server + wishes to indicate that congestion has been experienced, in which + case set the outgoing value to CE (=0b11). + + Alternate Behavior: Set the outgoing value to Not-ECT (=0b00). + + IPv4 Fragmentation fields + + Preferred Behavior: When the server sends a packet to a peer in + response to a Send indication containing the DONT-FRAGMENT + attribute, then set the DF bit in the outgoing IP header to 1. In + all other cases when sending an outgoing packet containing + application data (e.g., Data indication, ChannelData message, or + DONT-FRAGMENT attribute not included in the Send indication), copy + the DF bit from the DF bit of the incoming packet that contained + the application data. + + Set the other fragmentation fields (Identification, More + Fragments, Fragment Offset) as appropriate for a packet + originating from the server. + + Alternate Behavior: As described in the Preferred Behavior, except + always assume the incoming DF bit is 0. + + In both the Preferred and Alternate Behaviors, the resulting + packet may be too large for the outgoing link. If this is the + case, then the normal fragmentation rules apply [RFC1122]. + + IPv4 Options + + Preferred Behavior: The outgoing packet is sent without any IPv4 + options. + + Alternate Behavior: Same as preferred. + + + + + +Mahy, et al. Standards Track [Page 44] + +RFC 5766 TURN April 2010 + + +13. New STUN Methods + + This section lists the codepoints for the new STUN methods defined in + this specification. See elsewhere in this document for the semantics + of these new methods. + + 0x003 : Allocate (only request/response semantics defined) + 0x004 : Refresh (only request/response semantics defined) + 0x006 : Send (only indication semantics defined) + 0x007 : Data (only indication semantics defined) + 0x008 : CreatePermission (only request/response semantics defined + 0x009 : ChannelBind (only request/response semantics defined) + +14. New STUN Attributes + + This STUN extension defines the following new attributes: + + 0x000C: CHANNEL-NUMBER + 0x000D: LIFETIME + 0x0010: Reserved (was BANDWIDTH) + 0x0012: XOR-PEER-ADDRESS + 0x0013: DATA + 0x0016: XOR-RELAYED-ADDRESS + 0x0018: EVEN-PORT + 0x0019: REQUESTED-TRANSPORT + 0x001A: DONT-FRAGMENT + 0x0021: Reserved (was TIMER-VAL) + 0x0022: RESERVATION-TOKEN + + Some of these attributes have lengths that are not multiples of 4. + By the rules of STUN, any attribute whose length is not a multiple of + 4 bytes MUST be immediately followed by 1 to 3 padding bytes to + ensure the next attribute (if any) would start on a 4-byte boundary + (see [RFC5389]). + +14.1. CHANNEL-NUMBER + + The CHANNEL-NUMBER attribute contains the number of the channel. The + value portion of this attribute is 4 bytes long and consists of a 16- + bit unsigned integer, followed by a two-octet RFFU (Reserved For + Future Use) field, which MUST be set to 0 on transmission and MUST be + ignored on reception. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Channel Number | RFFU = 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +Mahy, et al. Standards Track [Page 45] + +RFC 5766 TURN April 2010 + + +14.2. LIFETIME + + The LIFETIME attribute represents the duration for which the server + will maintain an allocation in the absence of a refresh. The value + portion of this attribute is 4-bytes long and consists of a 32-bit + unsigned integral value representing the number of seconds remaining + until expiration. + +14.3. XOR-PEER-ADDRESS + + The XOR-PEER-ADDRESS specifies the address and port of the peer as + seen from the TURN server. (For example, the peer's server-reflexive + transport address if the peer is behind a NAT.) It is encoded in the + same way as XOR-MAPPED-ADDRESS [RFC5389]. + +14.4. DATA + + The DATA attribute is present in all Send and Data indications. The + value portion of this attribute is variable length and consists of + the application data (that is, the data that would immediately follow + the UDP header if the data was been sent directly between the client + and the peer). If the length of this attribute is not a multiple of + 4, then padding must be added after this attribute. + +14.5. XOR-RELAYED-ADDRESS + + The XOR-RELAYED-ADDRESS is present in Allocate responses. It + specifies the address and port that the server allocated to the + client. It is encoded in the same way as XOR-MAPPED-ADDRESS + [RFC5389]. + +14.6. EVEN-PORT + + This attribute allows the client to request that the port in the + relayed transport address be even, and (optionally) that the server + reserve the next-higher port number. The value portion of this + attribute is 1 byte long. Its format is: + + + + + + + + + + + + + + +Mahy, et al. Standards Track [Page 46] + +RFC 5766 TURN April 2010 + + + 0 + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |R| RFFU | + +-+-+-+-+-+-+-+-+ + + The value contains a single 1-bit flag: + + R: If 1, the server is requested to reserve the next-higher port + number (on the same IP address) for a subsequent allocation. If + 0, no such reservation is requested. + + The other 7 bits of the attribute's value must be set to zero on + transmission and ignored on reception. + + Since the length of this attribute is not a multiple of 4, padding + must immediately follow this attribute. + +14.7. REQUESTED-TRANSPORT + + This attribute is used by the client to request a specific transport + protocol for the allocated transport address. The value of this + attribute is 4 bytes with the following format: + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Protocol | RFFU | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The Protocol field specifies the desired protocol. The codepoints + used in this field are taken from those allowed in the Protocol field + in the IPv4 header and the NextHeader field in the IPv6 header + [Protocol-Numbers]. This specification only allows the use of + codepoint 17 (User Datagram Protocol). + + The RFFU field MUST be set to zero on transmission and MUST be + ignored on reception. It is reserved for future uses. + +14.8. DONT-FRAGMENT + + This attribute is used by the client to request that the server set + the DF (Don't Fragment) bit in the IP header when relaying the + application data onward to the peer. This attribute has no value + part and thus the attribute length field is 0. + + + + + + + +Mahy, et al. Standards Track [Page 47] + +RFC 5766 TURN April 2010 + + +14.9. RESERVATION-TOKEN + + The RESERVATION-TOKEN attribute contains a token that uniquely + identifies a relayed transport address being held in reserve by the + server. The server includes this attribute in a success response to + tell the client about the token, and the client includes this + attribute in a subsequent Allocate request to request the server use + that relayed transport address for the allocation. + + The attribute value is 8 bytes and contains the token value. + +15. New STUN Error Response Codes + + This document defines the following new error response codes: + + 403 (Forbidden): The request was valid but cannot be performed due + to administrative or similar restrictions. + + 437 (Allocation Mismatch): A request was received by the server that + requires an allocation to be in place, but no allocation exists, + or a request was received that requires no allocation, but an + allocation exists. + + 441 (Wrong Credentials): The credentials in the (non-Allocate) + request do not match those used to create the allocation. + + 442 (Unsupported Transport Protocol): The Allocate request asked the + server to use a transport protocol between the server and the peer + that the server does not support. NOTE: This does NOT refer to + the transport protocol used in the 5-tuple. + + 486 (Allocation Quota Reached): No more allocations using this + username can be created at the present time. + + 508 (Insufficient Capacity): The server is unable to carry out the + request due to some capacity limit being reached. In an Allocate + response, this could be due to the server having no more relayed + transport addresses available at that time, having none with the + requested properties, or the one that corresponds to the specified + reservation token is not available. + +16. Detailed Example + + This section gives an example of the use of TURN, showing in detail + the contents of the messages exchanged. The example uses the network + diagram shown in the Overview (Figure 1). + + + + + +Mahy, et al. Standards Track [Page 48] + +RFC 5766 TURN April 2010 + + + For each message, the attributes included in the message and their + values are shown. For convenience, values are shown in a human- + readable format rather than showing the actual octets; for example, + "XOR-RELAYED-ADDRESS=192.0.2.15:9000" shows that the XOR-RELAYED- + ADDRESS attribute is included with an address of 192.0.2.15 and a + port of 9000, here the address and port are shown before the xor-ing + is done. For attributes with string-like values (e.g., + SOFTWARE="Example client, version 1.03" and + NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm"), the value of the attribute + is shown in quotes for readability, but these quotes do not appear in + the actual value. + + TURN TURN Peer Peer + client server A B + | | | | + |--- Allocate request -------------->| | | + | Transaction-Id=0xA56250D3F17ABE679422DE85 | | + | SOFTWARE="Example client, version 1.03" | | + | LIFETIME=3600 (1 hour) | | | + | REQUESTED-TRANSPORT=17 (UDP) | | | + | DONT-FRAGMENT | | | + | | | | + |<-- Allocate error response --------| | | + | Transaction-Id=0xA56250D3F17ABE679422DE85 | | + | SOFTWARE="Example server, version 1.17" | | + | ERROR-CODE=401 (Unauthorized) | | | + | REALM="example.com" | | | + | NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" | | + | | | | + |--- Allocate request -------------->| | | + | Transaction-Id=0xC271E932AD7446A32C234492 | | + | SOFTWARE="Example client 1.03" | | | + | LIFETIME=3600 (1 hour) | | | + | REQUESTED-TRANSPORT=17 (UDP) | | | + | DONT-FRAGMENT | | | + | USERNAME="George" | | | + | REALM="example.com" | | | + | NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" | | + | MESSAGE-INTEGRITY=... | | | + | | | | + |<-- Allocate success response ------| | | + | Transaction-Id=0xC271E932AD7446A32C234492 | | + | SOFTWARE="Example server, version 1.17" | | + | LIFETIME=1200 (20 minutes) | | | + | XOR-RELAYED-ADDRESS=192.0.2.15:50000 | | + | XOR-MAPPED-ADDRESS=192.0.2.1:7000 | | + | MESSAGE-INTEGRITY=... | | | + + + + +Mahy, et al. Standards Track [Page 49] + +RFC 5766 TURN April 2010 + + + The client begins by selecting a host transport address to use for + the TURN session; in this example, the client has selected 10.1.1.2: + 49721 as shown in Figure 1. The client then sends an Allocate + request to the server at the server transport address. The client + randomly selects a 96-bit transaction id of + 0xA56250D3F17ABE679422DE85 for this transaction; this is encoded in + the transaction id field in the fixed header. The client includes a + SOFTWARE attribute that gives information about the client's + software; here the value is "Example client, version 1.03" to + indicate that this is version 1.03 of something called the Example + client. The client includes the LIFETIME attribute because it wishes + the allocation to have a longer lifetime than the default of 10 + minutes; the value of this attribute is 3600 seconds, which + corresponds to 1 hour. The client must always include a REQUESTED- + TRANSPORT attribute in an Allocate request and the only value allowed + by this specification is 17, which indicates UDP transport between + the server and the peers. The client also includes the DONT-FRAGMENT + attribute because it wishes to use the DONT-FRAGMENT attribute later + in Send indications; this attribute consists of only an attribute + header, there is no value part. We assume the client has not + recently interacted with the server, thus the client does not include + USERNAME, REALM, NONCE, or MESSAGE-INTEGRITY attribute. Finally, + note that the order of attributes in a message is arbitrary (except + for the MESSAGE-INTEGRITY and FINGERPRINT attributes) and the client + could have used a different order. + + Servers require any request to be authenticated. Thus, when the + server receives the initial Allocate request, it rejects the request + because the request does not contain the authentication attributes. + Following the procedures of the long-term credential mechanism of + STUN [RFC5389], the server includes an ERROR-CODE attribute with a + value of 401 (Unauthorized), a REALM attribute that specifies the + authentication realm used by the server (in this case, the server's + domain "example.com"), and a nonce value in a NONCE attribute. The + server also includes a SOFTWARE attribute that gives information + about the server's software. + + The client, upon receipt of the 401 error, re-attempts the Allocate + request, this time including the authentication attributes. The + client selects a new transaction id, and then populates the new + Allocate request with the same attributes as before. The client + includes a USERNAME attribute and uses the realm value received from + the server to help it determine which value to use; here the client + is configured to use the username "George" for the realm + "example.com". The client also includes the REALM and NONCE + attributes, which are just copied from the 401 error response. + Finally, the client includes a MESSAGE-INTEGRITY attribute as the + last attribute in the message, whose value is a Hashed Message + + + +Mahy, et al. Standards Track [Page 50] + +RFC 5766 TURN April 2010 + + + Authentication Code - Secure Hash Algorithm 1 (HMAC-SHA1) hash over + the contents of the message (shown as just "..." above); this HMAC- + SHA1 computation includes a password value. Thus, an attacker cannot + compute the message integrity value without somehow knowing the + secret password. + + The server, upon receipt of the authenticated Allocate request, + checks that everything is OK, then creates an allocation. The server + replies with an Allocate success response. The server includes a + LIFETIME attribute giving the lifetime of the allocation; here, the + server has reduced the client's requested 1-hour lifetime to just 20 + minutes, because this particular server doesn't allow lifetimes + longer than 20 minutes. The server includes an XOR-RELAYED-ADDRESS + attribute whose value is the relayed transport address of the + allocation. The server includes an XOR-MAPPED-ADDRESS attribute + whose value is the server-reflexive address of the client; this value + is not used otherwise in TURN but is returned as a convenience to the + client. The server includes a MESSAGE-INTEGRITY attribute to + authenticate the response and to ensure its integrity; note that the + response does not contain the USERNAME, REALM, and NONCE attributes. + The server also includes a SOFTWARE attribute. + + TURN TURN Peer Peer + client server A B + |--- CreatePermission request ------>| | | + | Transaction-Id=0xE5913A8F460956CA277D3319 | | + | XOR-PEER-ADDRESS=192.0.2.150:0 | | | + | USERNAME="George" | | | + | REALM="example.com" | | | + | NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" | | + | MESSAGE-INTEGRITY=... | | | + | | | | + |<-- CreatePermission success resp.--| | | + | Transaction-Id=0xE5913A8F460956CA277D3319 | | + | MESSAGE-INTEGRITY=... | | | + + The client then creates a permission towards Peer A in preparation + for sending it some application data. This is done through a + CreatePermission request. The XOR-PEER-ADDRESS attribute contains + the IP address for which a permission is established (the IP address + of peer A); note that the port number in the attribute is ignored + when used in a CreatePermission request, and here it has been set to + 0; also, note how the client uses Peer A's server-reflexive IP + address and not its (private) host address. The client uses the same + username, realm, and nonce values as in the previous request on the + allocation. Though it is allowed to do so, the client has chosen not + to include a SOFTWARE attribute in this request. + + + + +Mahy, et al. Standards Track [Page 51] + +RFC 5766 TURN April 2010 + + + The server receives the CreatePermission request, creates the + corresponding permission, and then replies with a CreatePermission + success response. Like the client, the server chooses not to include + the SOFTWARE attribute in its reply. Again, note how success + responses contain a MESSAGE-INTEGRITY attribute (assuming the server + uses the long-term credential mechanism), but no USERNAME, REALM, and + NONCE attributes. + + TURN TURN Peer Peer + client server A B + |--- Send indication --------------->| | | + | Transaction-Id=0x1278E9ACA2711637EF7D3328 | | + | XOR-PEER-ADDRESS=192.0.2.150:32102 | | + | DONT-FRAGMENT | | | + | DATA=... | | | + | |-- UDP dgm ->| | + | | data=... | | + | | | | + | |<- UDP dgm --| | + | | data=... | | + |<-- Data indication ----------------| | | + | Transaction-Id=0x8231AE8F9242DA9FF287FEFF | | + | XOR-PEER-ADDRESS=192.0.2.150:32102 | | + | DATA=... | | | + + The client now sends application data to Peer A using a Send + indication. Peer A's server-reflexive transport address is specified + in the XOR-PEER-ADDRESS attribute, and the application data (shown + here as just "...") is specified in the DATA attribute. The client + is doing a form of path MTU discovery at the application layer and + thus specifies (by including the DONT-FRAGMENT attribute) that the + server should set the DF bit in the UDP datagram to send to the peer. + Indications cannot be authenticated using the long-term credential + mechanism of STUN, so no MESSAGE-INTEGRITY attribute is included in + the message. An application wishing to ensure that its data is not + altered or forged must integrity-protect its data at the application + level. + + Upon receipt of the Send indication, the server extracts the + application data and sends it in a UDP datagram to Peer A, with the + relayed transport address as the source transport address of the + datagram, and with the DF bit set as requested. Note that, had the + client not previously established a permission for Peer A's server- + reflexive IP address, then the server would have silently discarded + the Send indication instead. + + + + + + +Mahy, et al. Standards Track [Page 52] + +RFC 5766 TURN April 2010 + + + Peer A then replies with its own UDP datagram containing application + data. The datagram is sent to the relayed transport address on the + server. When this arrives, the server creates a Data indication + containing the source of the UDP datagram in the XOR-PEER-ADDRESS + attribute, and the data from the UDP datagram in the DATA attribute. + The resulting Data indication is then sent to the client. + + TURN TURN Peer Peer + client server A B + |--- ChannelBind request ----------->| | | + | Transaction-Id=0x6490D3BC175AFF3D84513212 | | + | CHANNEL-NUMBER=0x4000 | | | + | XOR-PEER-ADDRESS=192.0.2.210:49191 | | + | USERNAME="George" | | | + | REALM="example.com" | | | + | NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" | | + | MESSAGE-INTEGRITY=... | | | + | | | | + |<-- ChannelBind success response ---| | | + | Transaction-Id=0x6490D3BC175AFF3D84513212 | | + | MESSAGE-INTEGRITY=... | | | + + The client now binds a channel to Peer B, specifying a free channel + number (0x4000) in the CHANNEL-NUMBER attribute, and Peer B's + transport address in the XOR-PEER-ADDRESS attribute. As before, the + client re-uses the username, realm, and nonce from its last request + in the message. + + Upon receipt of the request, the server binds the channel number to + the peer, installs a permission for Peer B's IP address, and then + replies with ChannelBind success response. + + TURN TURN Peer Peer + client server A B + |--- ChannelData ------------------->| | | + | Channel-number=0x4000 |--- UDP datagram --------->| + | Data=... | Data=... | + | | | | + | |<-- UDP datagram ----------| + | | Data=... | | + |<-- ChannelData --------------------| | | + | Channel-number=0x4000 | | | + | Data=... | | | + + The client now sends a ChannelData message to the server with data + destined for Peer B. The ChannelData message is not a STUN message, + and thus has no transaction id. Instead, it has only three fields: a + channel number, data, and data length; here the channel number field + + + +Mahy, et al. Standards Track [Page 53] + +RFC 5766 TURN April 2010 + + + is 0x4000 (the channel the client just bound to Peer B). When the + server receives the ChannelData message, it checks that the channel + is currently bound (which it is) and then sends the data onward to + Peer B in a UDP datagram, using the relayed transport address as the + source transport address and 192.0.2.210:49191 (the value of the XOR- + PEER-ADDRESS attribute in the ChannelBind request) as the destination + transport address. + + Later, Peer B sends a UDP datagram back to the relayed transport + address. This causes the server to send a ChannelData message to the + client containing the data from the UDP datagram. The server knows + to which client to send the ChannelData message because of the + relayed transport address at which the UDP datagram arrived, and + knows to use channel 0x4000 because this is the channel bound to + 192.0.2.210:49191. Note that if there had not been any channel + number bound to that address, the server would have used a Data + indication instead. + + TURN TURN Peer Peer + client server A B + |--- Refresh request --------------->| | | + | Transaction-Id=0x0864B3C27ADE9354B4312414 | | + | SOFTWARE="Example client 1.03" | | | + | USERNAME="George" | | | + | REALM="example.com" | | | + | NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" | | + | MESSAGE-INTEGRITY=... | | | + | | | | + |<-- Refresh error response ---------| | | + | Transaction-Id=0x0864B3C27ADE9354B4312414 | | + | SOFTWARE="Example server, version 1.17" | | + | ERROR-CODE=438 (Stale Nonce) | | | + | REALM="example.com" | | | + | NONCE="npSw1Xw239bBwGYhjNWgz2yH47sxB2j" | | + | | | | + |--- Refresh request --------------->| | | + | Transaction-Id=0x427BD3E625A85FC731DC4191 | | + | SOFTWARE="Example client 1.03" | | | + | USERNAME="George" | | | + | REALM="example.com" | | | + | NONCE="npSw1Xw239bBwGYhjNWgz2yH47sxB2j" | | + | MESSAGE-INTEGRITY=... | | | + | | | | + |<-- Refresh success response -------| | | + | Transaction-Id=0x427BD3E625A85FC731DC4191 | | + | SOFTWARE="Example server, version 1.17" | | + | LIFETIME=600 (10 minutes) | | | + + + + +Mahy, et al. Standards Track [Page 54] + +RFC 5766 TURN April 2010 + + + Sometime before the 20 minute lifetime is up, the client refreshes + the allocation. This is done using a Refresh request. As before, + the client includes the latest username, realm, and nonce values in + the request. The client also includes the SOFTWARE attribute, + following the recommended practice of always including this attribute + in Allocate and Refresh messages. When the server receives the + Refresh request, it notices that the nonce value has expired, and so + replies with 438 (Stale Nonce) error given a new nonce value. The + client then reattempts the request, this time with the new nonce + value. This second attempt is accepted, and the server replies with + a success response. Note that the client did not include a LIFETIME + attribute in the request, so the server refreshes the allocation for + the default lifetime of 10 minutes (as can be seen by the LIFETIME + attribute in the success response). + +17. Security Considerations + + This section considers attacks that are possible in a TURN + deployment, and discusses how they are mitigated by mechanisms in the + protocol or recommended practices in the implementation. + + Most of the attacks on TURN are mitigated by the server requiring + requests be authenticated. Thus, this specification requires the use + of authentication. The mandatory-to-implement mechanism is the long- + term credential mechanism of STUN. Other authentication mechanisms + of equal or stronger security properties may be used. However, it is + important to ensure that they can be invoked in an inter-operable + way. + +17.1. Outsider Attacks + + Outsider attacks are ones where the attacker has no credentials in + the system, and is attempting to disrupt the service seen by the + client or the server. + +17.1.1. Obtaining Unauthorized Allocations + + An attacker might wish to obtain allocations on a TURN server for any + number of nefarious purposes. A TURN server provides a mechanism for + sending and receiving packets while cloaking the actual IP address of + the client. This makes TURN servers an attractive target for + attackers who wish to use it to mask their true identity. + + An attacker might also wish to simply utilize the services of a TURN + server without paying for them. Since TURN services require + resources from the provider, it is anticipated that their usage will + come with a cost. + + + + +Mahy, et al. Standards Track [Page 55] + +RFC 5766 TURN April 2010 + + + These attacks are prevented using the long-term credential mechanism, + which allows the TURN server to determine the identity of the + requestor and whether the requestor is allowed to obtain the + allocation. + +17.1.2. Offline Dictionary Attacks + + The long-term credential mechanism used by TURN is subject to offline + dictionary attacks. An attacker that is capable of eavesdropping on + a message exchange between a client and server can determine the + password by trying a number of candidate passwords and seeing if one + of them is correct. This attack works when the passwords are low + entropy, such as a word from the dictionary. This attack can be + mitigated by using strong passwords with large entropy. In + situations where even stronger mitigation is required, TLS transport + between the client and the server can be used. + +17.1.3. Faked Refreshes and Permissions + + An attacker might wish to attack an active allocation by sending it a + Refresh request with an immediate expiration, in order to delete it + and disrupt service to the client. This is prevented by + authentication of refreshes. Similarly, an attacker wishing to send + CreatePermission requests to create permissions to undesirable + destinations is prevented from doing so through authentication. The + motivations for such an attack are described in Section 17.2. + +17.1.4. Fake Data + + An attacker might wish to send data to the client or the peer, as if + they came from the peer or client, respectively. To do that, the + attacker can send the client a faked Data Indication or ChannelData + message, or send the TURN server a faked Send Indication or + ChannelData message. + + Since indications and ChannelData messages are not authenticated, + this attack is not prevented by TURN. However, this attack is + generally present in IP-based communications and is not substantially + worsened by TURN. Consider a normal, non-TURN IP session between + hosts A and B. An attacker can send packets to B as if they came + from A by sending packets towards A with a spoofed IP address of B. + This attack requires the attacker to know the IP addresses of A and + B. With TURN, an attacker wishing to send packets towards a client + using a Data indication needs to know its IP address (and port), the + IP address and port of the TURN server, and the IP address and port + of the peer (for inclusion in the XOR-PEER-ADDRESS attribute). To + send a fake ChannelData message to a client, an attacker needs to + know the IP address and port of the client, the IP address and port + + + +Mahy, et al. Standards Track [Page 56] + +RFC 5766 TURN April 2010 + + + of the TURN server, and the channel number. This particular + combination is mildly more guessable than in the non-TURN case. + + These attacks are more properly mitigated by application-layer + authentication techniques. In the case of real-time traffic, usage + of SRTP [RFC3711] prevents these attacks. + + In some situations, the TURN server may be situated in the network + such that it is able to send to hosts to which the client cannot + directly send. This can happen, for example, if the server is + located behind a firewall that allows packets from outside the + firewall to be delivered to the server, but not to other hosts behind + the firewall. In these situations, an attacker could send the server + a Send indication with an XOR-PEER-ADDRESS attribute containing the + transport address of one of the other hosts behind the firewall. If + the server was to allow relaying of traffic to arbitrary peers, then + this would provide a way for the attacker to attack arbitrary hosts + behind the firewall. + + To mitigate this attack, TURN requires that the client establish a + permission to a host before sending it data. Thus, an attacker can + only attack hosts with which the client is already communicating, + unless the attacker is able to create authenticated requests. + Furthermore, the server administrator may configure the server to + restrict the range of IP addresses and ports to which it will relay + data. To provide even greater security, the server administrator can + require that the client use TLS for all communication between the + client and the server. + +17.1.5. Impersonating a Server + + When a client learns a relayed address from a TURN server, it uses + that relayed address in application protocols to receive traffic. + Therefore, an attacker wishing to intercept or redirect that traffic + might try to impersonate a TURN server and provide the client with a + faked relayed address. + + This attack is prevented through the long-term credential mechanism, + which provides message integrity for responses in addition to + verifying that they came from the server. Furthermore, an attacker + cannot replay old server responses as the transaction id in the STUN + header prevents this. Replay attacks are further thwarted through + frequent changes to the nonce value. + + + + + + + + +Mahy, et al. Standards Track [Page 57] + +RFC 5766 TURN April 2010 + + +17.1.6. Eavesdropping Traffic + + TURN concerns itself primarily with authentication and message + integrity. Confidentiality is only a secondary concern, as TURN + control messages do not include information that is particularly + sensitive. The primary protocol content of the messages is the IP + address of the peer. If it is important to prevent an eavesdropper + on a TURN connection from learning this, TURN can be run over TLS. + + Confidentiality for the application data relayed by TURN is best + provided by the application protocol itself, since running TURN over + TLS does not protect application data between the server and the + peer. If confidentiality of application data is important, then the + application should encrypt or otherwise protect its data. For + example, for real-time media, confidentiality can be provided by + using SRTP. + +17.1.7. TURN Loop Attack + + An attacker might attempt to cause data packets to loop indefinitely + between two TURN servers. The attack goes as follows. First, the + attacker sends an Allocate request to server A, using the source + address of server B. Server A will send its response to server B, + and for the attack to succeed, the attacker must have the ability to + either view or guess the contents of this response, so that the + attacker can learn the allocated relayed transport address. The + attacker then sends an Allocate request to server B, using the source + address of server A. Again, the attacker must be able to view or + guess the contents of the response, so it can send learn the + allocated relayed transport address. Using the same spoofed source + address technique, the attacker then binds a channel number on server + A to the relayed transport address on server B, and similarly binds + the same channel number on server B to the relayed transport address + on server A. Finally, the attacker sends a ChannelData message to + server A. + + The result is a data packet that loops from the relayed transport + address on server A to the relayed transport address on server B, + then from server B's transport address to server A's transport + address, and then around the loop again. + + This attack is mitigated as follows. By requiring all requests to be + authenticated and/or by randomizing the port number allocated for the + relayed transport address, the server forces the attacker to either + intercept or view responses sent to a third party (in this case, the + other server) so that the attacker can authenticate the requests and + learn the relayed transport address. Without one of these two + measures, an attacker can guess the contents of the responses without + + + +Mahy, et al. Standards Track [Page 58] + +RFC 5766 TURN April 2010 + + + needing to see them, which makes the attack much easier to perform. + Furthermore, by requiring authenticated requests, the server forces + the attacker to have credentials acceptable to the server, which + turns this from an outsider attack into an insider attack and allows + the attack to be traced back to the client initiating it. + + The attack can be further mitigated by imposing a per-username limit + on the bandwidth used to relay data by allocations owned by that + username, to limit the impact of this attack on other allocations. + More mitigation can be achieved by decrementing the TTL when relaying + data packets (if the underlying OS allows this). + +17.2. Firewall Considerations + + A key security consideration of TURN is that TURN should not weaken + the protections afforded by firewalls deployed between a client and a + TURN server. It is anticipated that TURN servers will often be + present on the public Internet, and clients may often be inside + enterprise networks with corporate firewalls. If TURN servers + provide a 'backdoor' for reaching into the enterprise, TURN will be + blocked by these firewalls. + + TURN servers therefore emulate the behavior of NAT devices that + implement address-dependent filtering [RFC4787], a property common in + many firewalls as well. When a NAT or firewall implements this + behavior, packets from an outside IP address are only allowed to be + sent to an internal IP address and port if the internal IP address + and port had recently sent a packet to that outside IP address. TURN + servers introduce the concept of permissions, which provide exactly + this same behavior on the TURN server. An attacker cannot send a + packet to a TURN server and expect it to be relayed towards the + client, unless the client has tried to contact the attacker first. + + It is important to note that some firewalls have policies that are + even more restrictive than address-dependent filtering. Firewalls + can also be configured with address- and port-dependent filtering, or + can be configured to disallow inbound traffic entirely. In these + cases, if a client is allowed to connect the TURN server, + communications to the client will be less restrictive than what the + firewall would normally allow. + +17.2.1. Faked Permissions + + In firewalls and NAT devices, permissions are granted implicitly + through the traversal of a packet from the inside of the network + towards the outside peer. Thus, a permission cannot, by definition, + be created by any entity except one inside the firewall or NAT. With + TURN, this restriction no longer holds. Since the TURN server sits + + + +Mahy, et al. Standards Track [Page 59] + +RFC 5766 TURN April 2010 + + + outside the firewall, at attacker outside the firewall can now send a + message to the TURN server and try to create a permission for itself. + + This attack is prevented because all messages that create permissions + (i.e., ChannelBind and CreatePermission) are authenticated. + +17.2.2. Blacklisted IP Addresses + + Many firewalls can be configured with blacklists that prevent a + client behind the firewall from sending packets to, or receiving + packets from, ranges of blacklisted IP addresses. This is + accomplished by inspecting the source and destination addresses of + packets entering and exiting the firewall, respectively. + + This feature is also present in TURN, since TURN servers are allowed + to arbitrarily restrict the range of addresses of peers that they + will relay to. + +17.2.3. Running Servers on Well-Known Ports + + A malicious client behind a firewall might try to connect to a TURN + server and obtain an allocation which it then uses to run a server. + For example, a client might try to run a DNS server or FTP server. + + This is not possible in TURN. A TURN server will never accept + traffic from a peer for which the client has not installed a + permission. Thus, peers cannot just connect to the allocated port in + order to obtain the service. + +17.3. Insider Attacks + + In insider attacks, a client has legitimate credentials but defies + the trust relationship that goes with those credentials. These + attacks cannot be prevented by cryptographic means but need to be + considered in the design of the protocol. + +17.3.1. DoS against TURN Server + + A client wishing to disrupt service to other clients might obtain an + allocation and then flood it with traffic, in an attempt to swamp the + server and prevent it from servicing other legitimate clients. This + is mitigated by the recommendation that the server limit the amount + of bandwidth it will relay for a given username. This won't prevent + a client from sending a large amount of traffic, but it allows the + server to immediately discard traffic in excess. + + Since each allocation uses a port number on the IP address of the + TURN server, the number of allocations on a server is finite. An + + + +Mahy, et al. Standards Track [Page 60] + +RFC 5766 TURN April 2010 + + + attacker might attempt to consume all of them by requesting a large + number of allocations. This is prevented by the recommendation that + the server impose a limit of the number of allocations active at a + time for a given username. + +17.3.2. Anonymous Relaying of Malicious Traffic + + TURN servers provide a degree of anonymization. A client can send + data to peers without revealing its own IP address. TURN servers may + therefore become attractive vehicles for attackers to launch attacks + against targets without fear of detection. Indeed, it is possible + for a client to chain together multiple TURN servers, such that any + number of relays can be used before a target receives a packet. + + Administrators who are worried about this attack can maintain logs + that capture the actual source IP and port of the client, and perhaps + even every permission that client installs. This will allow for + forensic tracing to determine the original source, should it be + discovered that an attack is being relayed through a TURN server. + +17.3.3. Manipulating Other Allocations + + An attacker might attempt to disrupt service to other users of the + TURN server by sending Refresh requests or CreatePermission requests + that (through source address spoofing) appear to be coming from + another user of the TURN server. TURN prevents this by requiring + that the credentials used in CreatePermission, Refresh, and + ChannelBind messages match those used to create the initial + allocation. Thus, the fake requests from the attacker will be + rejected. + +17.4. Other Considerations + + Any relay addresses learned through an Allocate request will not + operate properly with IPsec Authentication Header (AH) [RFC4302] in + transport or tunnel mode. However, tunnel-mode IPsec Encapsulating + Security Payload (ESP) [RFC4303] should still operate. + +18. IANA Considerations + + Since TURN is an extension to STUN [RFC5389], the methods, + attributes, and error codes defined in this specification are new + methods, attributes, and error codes for STUN. IANA has added these + new protocol elements to the IANA registry of STUN protocol elements. + + The codepoints for the new STUN methods defined in this specification + are listed in Section 13. + + + + +Mahy, et al. Standards Track [Page 61] + +RFC 5766 TURN April 2010 + + + The codepoints for the new STUN attributes defined in this + specification are listed in Section 14. + + The codepoints for the new STUN error codes defined in this + specification are listed in Section 15. + + IANA has allocated the SRV service name of "turn" for TURN over UDP + or TCP, and the service name of "turns" for TURN over TLS. + + IANA has created a registry for TURN channel numbers, initially + populated as follows: + + 0x0000 through 0x3FFF: Reserved and not available for use, since + they conflict with the STUN header. + + 0x4000 through 0x7FFF: A TURN implementation is free to use + channel numbers in this range. + + 0x8000 through 0xFFFF: Unassigned. + + Any change to this registry must be made through an IETF Standards + Action. + +19. IAB Considerations + + The IAB has studied the problem of "Unilateral Self Address Fixing" + (UNSAF), which is the general process by which a client attempts to + determine its address in another realm on the other side of a NAT + through a collaborative protocol-reflection mechanism [RFC3424]. The + TURN extension is an example of a protocol that performs this type of + function. The IAB has mandated that any protocols developed for this + purpose document a specific set of considerations. These + considerations and the responses for TURN are documented in this + section. + + Consideration 1: Precise definition of a specific, limited-scope + problem that is to be solved with the UNSAF proposal. A short-term + fix should not be generalized to solve other problems. Such + generalizations lead to the prolonged dependence on and usage of the + supposed short-term fix -- meaning that it is no longer accurate to + call it "short-term". + + Response: TURN is a protocol for communication between a relay (= + TURN server) and its client. The protocol allows a client that is + behind a NAT to obtain and use a public IP address on the relay. As + a convenience to the client, TURN also allows the client to determine + its server-reflexive transport address. + + + + +Mahy, et al. Standards Track [Page 62] + +RFC 5766 TURN April 2010 + + + Consideration 2: Description of an exit strategy/transition plan. + The better short-term fixes are the ones that will naturally see less + and less use as the appropriate technology is deployed. + + Response: TURN will no longer be needed once there are no longer any + NATs. Unfortunately, as of the date of publication of this document, + it no longer seems very likely that NATs will go away any time soon. + However, the need for TURN will also decrease as the number of NATs + with the mapping property of Endpoint-Independent Mapping [RFC4787] + increases. + + Consideration 3: Discussion of specific issues that may render + systems more "brittle". For example, approaches that involve using + data at multiple network layers create more dependencies, increase + debugging challenges, and make it harder to transition. + + Response: TURN is "brittle" in that it requires the NAT bindings + between the client and the server to be maintained unchanged for the + lifetime of the allocation. This is typically done using keep- + alives. If this is not done, then the client will lose its + allocation and can no longer exchange data with its peers. + + Consideration 4: Identify requirements for longer-term, sound + technical solutions; contribute to the process of finding the right + longer-term solution. + + Response: The need for TURN will be reduced once NATs implement the + recommendations for NAT UDP behavior documented in [RFC4787]. + Applications are also strongly urged to use ICE [RFC5245] to + communicate with peers; though ICE uses TURN, it does so only as a + last resort, and uses it in a controlled manner. + + Consideration 5: Discussion of the impact of the noted practical + issues with existing deployed NATs and experience reports. + + Response: Some NATs deployed today exhibit a mapping behavior other + than Endpoint-Independent mapping. These NATs are difficult to work + with, as they make it difficult or impossible for protocols like ICE + to use server-reflexive transport addresses on those NATs. A client + behind such a NAT is often forced to use a relay protocol like TURN + because "UDP hole punching" techniques [RFC5128] do not work. + +20. Acknowledgements + + The authors would like to thank the various participants in the + BEHAVE working group for their many comments on this document. Marc + Petit-Huguenin, Remi Denis-Courmont, Jason Fischl, Derek MacDonald, + Scott Godin, Cullen Jennings, Lars Eggert, Magnus Westerlund, Benny + + + +Mahy, et al. Standards Track [Page 63] + +RFC 5766 TURN April 2010 + + + Prijono, and Eric Rescorla have been particularly helpful, with Eric + suggesting the channel allocation mechanism, Cullen suggesting an + earlier version of the EVEN-PORT mechanism, and Marc spending many + hours implementing the preliminary versions to look for problems. + Christian Huitema was an early contributor to this document and was a + co-author on the first few versions. Finally, the authors would like + to thank Dan Wing for both his contributions to the text and his huge + help in restarting progress on this document after work had stalled. + +21. References + +21.1. Normative References + + [RFC5389] Rosenberg, J., Mahy, R., Matthews, P., and D. + Wing, "Session Traversal Utilities for NAT + (STUN)", RFC 5389, October 2008. + + [RFC2119] Bradner, S., "Key words for use in RFCs to + Indicate Requirement Levels", BCP 14, RFC 2119, + March 1997. + + [RFC2474] Nichols, K., Blake, S., Baker, F., and D. Black, + "Definition of the Differentiated Services Field + (DS Field) in the IPv4 and IPv6 Headers", + RFC 2474, December 1998. + + [RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, "The + Addition of Explicit Congestion Notification + (ECN) to IP", RFC 3168, September 2001. + + [RFC1122] Braden, R., "Requirements for Internet Hosts - + Communication Layers", STD 3, RFC 1122, + October 1989. + +21.2. Informative References + + [RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", + RFC 1191, November 1990. + + [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC1918] Rekhter, Y., Moskowitz, R., Karrenberg, D., + Groot, G., and E. Lear, "Address Allocation for + Private Internets", BCP 5, RFC 1918, + February 1996. + + + + + +Mahy, et al. Standards Track [Page 64] + +RFC 5766 TURN April 2010 + + + [RFC3424] Daigle, L. and IAB, "IAB Considerations for + UNilateral Self-Address Fixing (UNSAF) Across + Network Address Translation", RFC 3424, + November 2002. + + [RFC4787] Audet, F. and C. Jennings, "Network Address + Translation (NAT) Behavioral Requirements for + Unicast UDP", BCP 127, RFC 4787, January 2007. + + [RFC5245] Rosenberg, J., "Interactive Connectivity + Establishment (ICE): A Protocol for Network + Address Translator (NAT) Traversal for + Offer/Answer Protocols", RFC 5245, April 2010. + + [TURN-TCP] Perreault, S. and J. Rosenberg, "Traversal Using + Relays around NAT (TURN) Extensions for TCP + Allocations", Work in Progress, March 2010. + + [TURN-IPv6] Perreault, S., Camarillo, G., and O. Novo, + "Traversal Using Relays around NAT (TURN) + Extension for IPv6", Work in Progress, March + 2010. + + [TSVWG-PORT] Larsen, M. and F. Gont, "Port Randomization", + Work in Progress, April 2010. + + [RFC5128] Srisuresh, P., Ford, B., and D. Kegel, "State of + Peer-to-Peer (P2P) Communication across Network + Address Translators (NATs)", RFC 5128, + March 2008. + + [RFC1928] Leech, M., Ganis, M., Lee, Y., Kuris, R., + Koblas, D., and L. Jones, "SOCKS Protocol + Version 5", RFC 1928, March 1996. + + [RFC3550] Schulzrinne, H., Casner, S., Frederick, R., and + V. Jacobson, "RTP: A Transport Protocol for + Real-Time Applications", STD 64, RFC 3550, + July 2003. + + [RFC3711] Baugher, M., McGrew, D., Naslund, M., Carrara, + E., and K. Norrman, "The Secure Real-time + Transport Protocol (SRTP)", RFC 3711, + March 2004. + + [RFC4302] Kent, S., "IP Authentication Header", RFC 4302, + December 2005. + + + + +Mahy, et al. Standards Track [Page 65] + +RFC 5766 TURN April 2010 + + + [RFC4303] Kent, S., "IP Encapsulating Security Payload + (ESP)", RFC 4303, December 2005. + + [RFC4821] Mathis, M. and J. Heffner, "Packetization Layer + Path MTU Discovery", RFC 4821, March 2007. + + [RFC3261] Rosenberg, J., Schulzrinne, H., Camarillo, G., + Johnston, A., Peterson, J., Sparks, R., Handley, + M., and E. Schooler, "SIP: Session Initiation + Protocol", RFC 3261, June 2002. + + [MMUSIC-ICE-NONSIP] Rosenberg, J., "Guidelines for Usage of + Interactive Connectivity Establishment (ICE) by + non Session Initiation Protocol (SIP) + Protocols", Work in Progress, July 2008. + + [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, + "Randomness Requirements for Security", BCP 106, + RFC 4086, June 2005. + + [Frag-Harmful] Kent and Mogul, "Fragmentation Considered + Harmful". Proc. SIGCOMM '87, vol. 17, No. 5, + October 1987 + + [Port-Numbers] "IANA Port Numbers Registry", + . + + [Protocol-Numbers] "IANA Protocol Numbers Registry", 2005, + . + + + + + + + + + + + + + + + + + + + + + + +Mahy, et al. Standards Track [Page 66] + +RFC 5766 TURN April 2010 + + +Authors' Addresses + + Rohan Mahy + Unaffiliated + + EMail: rohan@ekabal.com + + + Philip Matthews + Alcatel-Lucent + 600 March Road + Ottawa, Ontario + Canada + + EMail: philip_matthews@magma.ca + + + Jonathan Rosenberg + jdrosen.net + Monmouth, NJ + USA + + EMail: jdrosen@jdrosen.net + URI: http://www.jdrosen.net + + + + + + + + + + + + + + + + + + + + + + + + + + + +Mahy, et al. Standards Track [Page 67] + diff --git a/src/alloc.rs b/src/alloc.rs new file mode 100644 index 0000000..76658ef --- /dev/null +++ b/src/alloc.rs @@ -0,0 +1,63 @@ +use std::collections::HashMap; +use std::net::SocketAddr; +use std::sync::{Arc, Mutex}; +use tokio::net::UdpSocket; +use tracing::info; + +#[derive(Clone)] +pub struct Allocation { + pub client: SocketAddr, + pub relay_addr: SocketAddr, + // keep the socket so it stays bound + _socket: Arc, +} + +#[derive(Clone, Default)] +pub struct AllocationManager { + inner: Arc>>, +} + +impl AllocationManager { + pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(HashMap::new())) } } + + /// Create a relay UDP socket for the given client and spawn a relay loop that forwards + /// any packets received on the relay socket back to the client via the provided server socket. + pub async fn allocate_for(&self, client: SocketAddr, server_sock: Arc) -> anyhow::Result { + // bind relay socket to OS-chosen port + let relay = UdpSocket::bind("0.0.0.0:0").await?; + let relay_local = relay.local_addr()?; + let relay_arc = Arc::new(relay); + + // spawn relay loop + let relay_clone = relay_arc.clone(); + let server_sock_clone = server_sock.clone(); + let client_clone = client; + tokio::spawn(async move { + let mut buf = vec![0u8; 2048]; + loop { + match relay_clone.recv_from(&mut buf).await { + Ok((len, src)) => { + info!("relay got {} bytes from {} for client {}", len, src, client_clone); + // forward to client via server socket + let _ = server_sock_clone.send_to(&buf[..len], client_clone).await; + } + Err(e) => { + tracing::error!("relay socket error: {:?}", e); + break; + } + } + } + }); + + let alloc = Allocation { client, relay_addr: relay_local, _socket: relay_arc }; + tracing::info!("created allocation for {} -> {}", client, relay_local); + let mut m = self.inner.lock().unwrap(); + m.insert(client, alloc); + Ok(relay_local) + } + + pub fn get_allocation(&self, client: &SocketAddr) -> Option { + let m = self.inner.lock().unwrap(); + m.get(client).cloned() + } +} diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..1b80eee --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,46 @@ +use async_trait::async_trait; +use std::sync::Arc; +use crate::traits::CredentialStore; + +/// Simple in-memory credential store for MVP +#[derive(Clone, Default)] +pub struct InMemoryStore { + // simple map; for production replace with DB-backed store + inner: Arc>>, +} + +impl InMemoryStore { + pub fn new() -> Self { + Self { inner: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())) } + } + + pub fn insert(&self, user: impl Into, password: impl Into) { + let mut m = self.inner.lock().unwrap(); + m.insert(user.into(), password.into()); + } +} + +#[async_trait] +impl CredentialStore for InMemoryStore { + async fn get_password(&self, username: &str) -> Option { + let m = self.inner.lock().unwrap(); + m.get(username).cloned() + } +} + +/// Helper: compute MESSAGE-INTEGRITY (HMAC-SHA1 as bytes) +pub fn compute_hmac_sha1_bytes(key: &str, data: &[u8]) -> Vec { + use hmac::{Hmac, Mac}; + use sha1::Sha1; + type HmacSha1 = Hmac; + let mut mac = HmacSha1::new_from_slice(key.as_bytes()).expect("HMAC key"); + mac.update(data); + mac.finalize().into_bytes().to_vec() +} + +/// Compute A1 MD5(username:realm:password) as bytes for long-term credential derivation +pub fn compute_a1_md5(username: &str, realm: &str, password: &str) -> Vec { + let s = format!("{}:{}:{}", username, realm, password); + let digest = md5::compute(s.as_bytes()); + digest.0.to_vec() +} diff --git a/src/bin/allocate_smoke.rs b/src/bin/allocate_smoke.rs new file mode 100644 index 0000000..55a4a7f --- /dev/null +++ b/src/bin/allocate_smoke.rs @@ -0,0 +1,131 @@ +use bytes::BytesMut; +use niom_turn::constants::*; +use std::net::SocketAddr; +use tokio::net::UdpSocket; +use std::time::Duration; + +fn decode_xor_relayed_address_local(value: &[u8], _trans: &[u8;12]) -> Option { + if value.len() < 8 { return None; } + if value[1] != FAMILY_IPV4 { return None; } + let xport = u16::from_be_bytes([value[2], value[3]]); + let port = xport ^ ((MAGIC_COOKIE_U32 >> 16) as u16); + let cookie_bytes = MAGIC_COOKIE_U32.to_be_bytes(); + let mut ipb = [0u8;4]; + for i in 0..4 { ipb[i] = value[4 + i] ^ cookie_bytes[i]; } + let ip = std::net::Ipv4Addr::from(ipb); + Some(std::net::SocketAddr::new(std::net::IpAddr::V4(ip), port)) +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt::init(); + let server: SocketAddr = "127.0.0.1:3478".parse()?; + let local = UdpSocket::bind("0.0.0.0:0").await?; + + let username = "testuser"; + let password = "secretpassword"; + + // Build Allocate request (method METHOD_ALLOCATE) + let mut buf = BytesMut::new(); + buf.extend_from_slice(&METHOD_ALLOCATE.to_be_bytes()); // Allocate Request + buf.extend_from_slice(&0u16.to_be_bytes()); // length placeholder + buf.extend_from_slice(&MAGIC_COOKIE_U32.to_be_bytes()); + let trans = [13u8; 12]; + buf.extend_from_slice(&trans); + + // USERNAME + let uname = username.as_bytes(); + buf.extend_from_slice(&ATTR_USERNAME.to_be_bytes()); + buf.extend_from_slice(&(uname.len() as u16).to_be_bytes()); + buf.extend_from_slice(uname); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); } + + // MESSAGE-INTEGRITY placeholder + let mi_attr_offset = buf.len(); + buf.extend_from_slice(&ATTR_MESSAGE_INTEGRITY.to_be_bytes()); + buf.extend_from_slice(&(20u16).to_be_bytes()); + let mi_val_pos = buf.len(); + buf.extend_from_slice(&[0u8;20]); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); } + + // fix length + let total_len = (buf.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + buf[2] = len_bytes[0]; + buf[3] = len_bytes[1]; + + // compute HMAC over bytes up to MI attribute header + { + use hmac::{Hmac, Mac}; + use sha1::Sha1; + type HmacSha1 = Hmac; + let mut mac = HmacSha1::new_from_slice(password.as_bytes()).expect("HMAC key"); + mac.update(&buf[..mi_attr_offset]); + let res = mac.finalize().into_bytes(); + for i in 0..20 { buf[mi_val_pos + i] = res[i]; } + } + + // send Allocate + local.send_to(&buf, server).await?; + + // receive response + let mut r = vec![0u8; 1500]; + let (len, _addr) = local.recv_from(&mut r).await?; + println!("got {} bytes", len); + let resp = &r[..len]; + // expect success (RESP_BINDING_SUCCESS) with XOR-RELAYED-ADDRESS attr + if resp.len() < 20 { + anyhow::bail!("response too short"); + } + let typ = u16::from_be_bytes([resp[0], resp[1]]); + println!("resp type 0x{:04x}", typ); + if typ != RESP_BINDING_SUCCESS { + anyhow::bail!("expected success response, got 0x{:04x}", typ); + } + // parse attributes + let length = u16::from_be_bytes([resp[2], resp[3]]) as usize; + let total = 20 + length; + let mut offset = 20; + let mut relay_addr_opt: Option = None; + while offset + 4 <= total { + let atype = u16::from_be_bytes([resp[offset], resp[offset+1]]); + let alen = u16::from_be_bytes([resp[offset+2], resp[offset+3]]) as usize; + offset += 4; + if offset + alen > total { break; } + println!("attr type=0x{:04x} len={}", atype, alen); + println!("raw: {}", hex::encode(&resp[offset..offset+alen])); + if atype == ATTR_XOR_RELAYED_ADDRESS { + // XOR-RELAYED-ADDRESS: decode via local helper + if let Some(sa) = decode_xor_relayed_address_local(&resp[offset..offset+alen], &trans) { + relay_addr_opt = Some(sa); + } + } + offset += alen; + let pad = (4 - (alen % 4)) % 4; + offset += pad; + } + + let relay_addr = match relay_addr_opt { + Some(a) => a, + None => anyhow::bail!("no relay address in response"), + }; + + println!("got relayed addr: {}", relay_addr); + + // send test payload to relay addr + let payload = b"hello-relay"; + local.send_to(payload, relay_addr).await?; + + // wait for forwarded packet (should arrive via server socket) using tokio timeout + let mut buf2 = vec![0u8; 1500]; + match tokio::time::timeout(Duration::from_secs(2), local.recv_from(&mut buf2)).await { + Ok(Ok((l, src))) => { + println!("received {} bytes from {}", l, src); + let got = &buf2[..l]; + println!("payload: {:?}", got); + if got == payload { println!("relay test success"); Ok(()) } else { anyhow::bail!("payload mismatch") } + } + Ok(Err(e)) => anyhow::bail!("recv error: {:?}", e), + Err(_) => anyhow::bail!("no forwarded packet received: timeout"), + } +} diff --git a/src/bin/smoke_client.rs b/src/bin/smoke_client.rs new file mode 100644 index 0000000..e5dc235 --- /dev/null +++ b/src/bin/smoke_client.rs @@ -0,0 +1,64 @@ +use bytes::BytesMut; +use std::net::SocketAddr; +use tokio::net::UdpSocket; +use niom_turn::constants::*; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt::init(); + let server: SocketAddr = "127.0.0.1:3478".parse()?; + let local = UdpSocket::bind("0.0.0.0:0").await?; + + // Build a minimal STUN Binding Request with USERNAME and placeholder MESSAGE-INTEGRITY + let username = "testuser"; + let password = "secretpassword"; // matches server's in-memory creds + + let mut buf = BytesMut::new(); + buf.extend_from_slice(&METHOD_BINDING.to_be_bytes()); // Binding Request + buf.extend_from_slice(&0u16.to_be_bytes()); // length placeholder + buf.extend_from_slice(&MAGIC_COOKIE_U32.to_be_bytes()); + let trans = [7u8; 12]; + buf.extend_from_slice(&trans); + + // USERNAME + let uname = username.as_bytes(); + buf.extend_from_slice(&ATTR_USERNAME.to_be_bytes()); + buf.extend_from_slice(&(uname.len() as u16).to_be_bytes()); + buf.extend_from_slice(uname); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); } + + // MESSAGE-INTEGRITY placeholder + let mi_attr_offset = buf.len(); + buf.extend_from_slice(&ATTR_MESSAGE_INTEGRITY.to_be_bytes()); + buf.extend_from_slice(&(20u16).to_be_bytes()); + let mi_val_pos = buf.len(); + buf.extend_from_slice(&[0u8;20]); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); } + + // fix length + let total_len = (buf.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + buf[2] = len_bytes[0]; + buf[3] = len_bytes[1]; + + // compute HMAC over bytes up to MI attribute header + { + use hmac::{Hmac, Mac}; + use sha1::Sha1; + type HmacSha1 = Hmac; + let mut mac = HmacSha1::new_from_slice(password.as_bytes()).expect("HMAC key"); + mac.update(&buf[..mi_attr_offset]); + let res = mac.finalize().into_bytes(); + for i in 0..20 { buf[mi_val_pos + i] = res[i]; } + } + + // send + local.send_to(&buf, server).await?; + + let mut r = vec![0u8; 1500]; + let (len, addr) = local.recv_from(&mut r).await?; + println!("got {} bytes from {}", len, addr); + // dump hex + println!("{:02x?}", &r[..len]); + Ok(()) +} diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..686a3f9 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,24 @@ +//! Central constants for STUN/TURN implementations (magic cookie, attribute types, methods) + +pub const MAGIC_COOKIE_U32: u32 = 0x2112A442; +pub const MAGIC_COOKIE_BYTES: [u8;4] = MAGIC_COOKIE_U32.to_be_bytes(); + +// STUN Methods/Message Types (only those used in this MVP) +pub const METHOD_BINDING: u16 = 0x0001; +pub const METHOD_ALLOCATE: u16 = 0x0003; + +// Common response/error types +pub const RESP_BINDING_SUCCESS: u16 = 0x0101; + +// Common attribute types +pub const ATTR_USERNAME: u16 = 0x0006; +pub const ATTR_MESSAGE_INTEGRITY: u16 = 0x0008; +pub const ATTR_REALM: u16 = 0x0014; +pub const ATTR_NONCE: u16 = 0x0015; + +// TURN attrs +pub const ATTR_XOR_RELAYED_ADDRESS: u16 = 0x0016; + +// Some helper values +pub const FAMILY_IPV4: u8 = 0x01; + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2865e6e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,11 @@ +//! Library root for niom-turn shared modules +pub mod constants; +pub mod stun; +pub mod auth; +pub mod traits; +pub mod models; +pub mod alloc; + +pub use crate::auth::*; +pub use crate::stun::*; +pub use crate::alloc::*; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c64d728 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,160 @@ +use std::net::SocketAddr; +use std::sync::Arc; +use tokio::net::UdpSocket; +use tracing::{info, error}; + +mod stun; +mod auth; +mod traits; +mod models; +mod alloc; +mod constants; +use crate::constants::*; +use crate::auth::InMemoryStore; +use crate::stun::{parse_message, build_401_response}; +use crate::traits::CredentialStore; +// use crate::models::stun::StunHeader; // currently unused +use crate::alloc::AllocationManager; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt::init(); + + info!("niom-turn starting"); + + // config + let bind_addr: SocketAddr = "0.0.0.0:3478".parse()?; + + // Initialize credential store (MVP demo user) + let creds = InMemoryStore::new(); + creds.insert("testuser", "secretpassword"); + + // UDP listener for TURN/STUN + let udp = UdpSocket::bind(bind_addr).await?; + let udp = Arc::new(udp); + + // allocation manager + let alloc_mgr = AllocationManager::new(); + + // spawn packet handling loop + let udp_clone = udp.clone(); + let creds_clone = creds.clone(); + let alloc_clone = alloc_mgr.clone(); + tokio::spawn(async move { + if let Err(e) = udp_reader_loop(udp_clone, creds_clone, alloc_clone).await { + error!("udp loop error: {:?}", e); + } + }); + + // keep running + loop { + tokio::time::sleep(std::time::Duration::from_secs(60)).await; + } +} + +async fn udp_reader_loop(udp: Arc, creds: InMemoryStore, allocs: AllocationManager) -> anyhow::Result<()> { + let mut buf = vec![0u8; 1500]; + loop { + let (len, peer) = udp.recv_from(&mut buf).await?; + tracing::debug!("got {} bytes from {}", len, peer); + + // Minimal STUN/TURN detection: parse STUN messages and send 401 challenge + if let Ok(msg) = parse_message(&buf[..len]) { + tracing::info!("STUN/TURN message from {} type=0x{:04x} len={}", peer, msg.header.msg_type, len); + // If MESSAGE-INTEGRITY present, attempt validation using credential store + if let Some(_mi_attr) = crate::stun::find_message_integrity(&msg) { + // For MVP we expect username attribute (USERNAME) to be present + let username_attr = msg.attributes.iter().find(|a| a.typ == ATTR_USERNAME); + if let Some(u) = username_attr { + if let Ok(username) = std::str::from_utf8(&u.value) { + // lookup password + let store = creds.clone(); + let pw = store.get_password(username).await; + if let Some(password) = pw { + let valid = crate::stun::validate_message_integrity(&msg, &password); + if valid { + tracing::info!("MI valid for user {}", username); + // If this is an Allocate request, perform allocation + if msg.header.msg_type == METHOD_ALLOCATE { + match allocs.allocate_for(peer, udp.clone()).await { + Ok(relay_addr) => { + use bytes::BytesMut; + let mut out = BytesMut::new(); + out.extend_from_slice(&RESP_BINDING_SUCCESS.to_be_bytes()); + out.extend_from_slice(&0u16.to_be_bytes()); + out.extend_from_slice(&MAGIC_COOKIE_U32.to_be_bytes()); + out.extend_from_slice(&msg.header.transaction_id); + // RFC: XOR-RELAYED-ADDRESS (0x0016) + let attr_val = crate::stun::encode_xor_relayed_address(&relay_addr, &msg.header.transaction_id); + out.extend_from_slice(&ATTR_XOR_RELAYED_ADDRESS.to_be_bytes()); + out.extend_from_slice(&((attr_val.len() as u16).to_be_bytes())); + out.extend_from_slice(&attr_val); + while (out.len() % 4) != 0 { out.extend_from_slice(&[0]); } + let total_len = (out.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + out[2] = len_bytes[0]; out[3] = len_bytes[1]; + let vec_out = out.to_vec(); + tracing::info!("sending allocate success (mi-valid) -> {} bytes hex={} ", vec_out.len(), hex::encode(&vec_out)); + let _ = udp.send_to(&vec_out, &peer).await; + continue; + } + Err(e) => tracing::error!("allocate failed after MI valid: {:?}", e), + } + } + // default success response + let resp = crate::stun::build_success_response(&msg.header); + let _ = udp.send_to(&resp, &peer).await; + continue; + } else { + tracing::info!("MI invalid for user {}", username); + } + } else { + tracing::info!("unknown user {}", username); + } + } + } + } + // If it's an Allocate request (TURN method ALLOCATE) and MI valid, allocate a relay socket + if msg.header.msg_type == METHOD_ALLOCATE { + // If we reach here without MI, still attempt allocation but we will send a 401 earlier + let relay = allocs.allocate_for(peer, udp.clone()).await; + match relay { + Ok(relay_addr) => { + use bytes::BytesMut; + let mut out = BytesMut::new(); + out.extend_from_slice(&RESP_BINDING_SUCCESS.to_be_bytes()); + out.extend_from_slice(&0u16.to_be_bytes()); + out.extend_from_slice(&MAGIC_COOKIE_U32.to_be_bytes()); + out.extend_from_slice(&msg.header.transaction_id); + let attr_val = crate::stun::encode_xor_relayed_address(&relay_addr, &msg.header.transaction_id); + out.extend_from_slice(&ATTR_XOR_RELAYED_ADDRESS.to_be_bytes()); + out.extend_from_slice(&((attr_val.len() as u16).to_be_bytes())); + out.extend_from_slice(&attr_val); + while (out.len() % 4) != 0 { out.extend_from_slice(&[0]); } + let total_len = (out.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + out[2] = len_bytes[0]; out[3] = len_bytes[1]; + let vec_out = out.to_vec(); + tracing::info!("sending allocate success (no-mi) -> {} bytes hex={} ", vec_out.len(), hex::encode(&vec_out)); + let _ = udp.send_to(&vec_out, &peer).await; + } + Err(e) => { + error!("allocate failed: {:?}", e); + } + } + continue; + } + + // default: send 401 challenge + let nonce = format!("nonce-{}", uuid::Uuid::new_v4()); + let resp = build_401_response(&msg.header, "niom-turn.local", &nonce, 401); + if let Err(e) = udp.send_to(&resp, &peer).await { + error!("failed to send 401: {:?}", e); + } + } else { + tracing::debug!("Non-STUN or parse error from {} len={}", peer, len); + } + } +} + +// existing helper functions moved to stun.rs diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..2380ff3 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1,3 @@ +pub mod stun; + +pub use stun::{StunHeader, StunAttribute, StunMessage}; diff --git a/src/models/stun.rs b/src/models/stun.rs new file mode 100644 index 0000000..9f4c10e --- /dev/null +++ b/src/models/stun.rs @@ -0,0 +1,22 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StunHeader { + pub msg_type: u16, + pub length: u16, + pub cookie: u32, + pub transaction_id: [u8; 12], +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StunAttribute { + pub typ: u16, + pub value: Vec, + /// byte offset in the original message where the attribute header starts (type field) + pub offset: usize, +} + +#[derive(Debug, Clone)] +pub struct StunMessage { + pub header: StunHeader, + pub attributes: Vec, + pub raw: Vec, +} diff --git a/src/stun.rs b/src/stun.rs new file mode 100644 index 0000000..58c0232 --- /dev/null +++ b/src/stun.rs @@ -0,0 +1,261 @@ +use std::convert::TryInto; +use crate::models::stun::{StunHeader, StunAttribute, StunMessage}; +use crate::constants::*; + +#[derive(thiserror::Error, Debug)] +pub enum ParseError { + #[error("too short")] TooShort, + #[error("invalid magic cookie")] InvalidCookie, + #[error("attribute overflow")] AttrOverflow, +} + +pub fn parse_message(buf: &[u8]) -> Result { + if buf.len() < 20 { return Err(ParseError::TooShort); } + let msg_type = u16::from_be_bytes(buf[0..2].try_into().unwrap()); + let length = u16::from_be_bytes(buf[2..4].try_into().unwrap()); + let cookie = u32::from_be_bytes(buf[4..8].try_into().unwrap()); + if cookie != MAGIC_COOKIE_U32 { return Err(ParseError::InvalidCookie); } + let mut trans = [0u8; 12]; + trans.copy_from_slice(&buf[8..20]); + + let mut attrs = Vec::new(); + let mut offset = 20usize; + let total_len = (length as usize) + 20; + if buf.len() < total_len { return Err(ParseError::TooShort); } + + while offset + 4 <= total_len { + let typ = u16::from_be_bytes(buf[offset..offset+2].try_into().unwrap()); + let attr_len = u16::from_be_bytes(buf[offset+2..offset+4].try_into().unwrap()) as usize; + let attr_header_offset = offset; + offset += 4; + if offset + attr_len > total_len { return Err(ParseError::AttrOverflow); } + let value = buf[offset..offset+attr_len].to_vec(); + attrs.push(StunAttribute { typ, value, offset: attr_header_offset }); + offset += attr_len; + // padding to 32-bit boundary + let pad = (4 - (attr_len % 4)) % 4; + offset += pad; + } + + Ok(StunMessage { + header: StunHeader { msg_type, length, cookie, transaction_id: trans }, + attributes: attrs, + raw: buf[..total_len].to_vec(), + }) +} + +/// Build a minimal 401 error response (REALM + NONCE). Returns the bytes to send. +pub fn build_401_response(req: &StunHeader, realm: &str, nonce: &str, _err_code: u16) -> Vec { + use bytes::BytesMut; + let mut buf = BytesMut::new(); + // Error response type for TURN often uses same method with error bit set; here we reuse 0x0111 placeholder + let msg_type: u16 = 0x0111; + buf.extend_from_slice(&msg_type.to_be_bytes()); + buf.extend_from_slice(&0u16.to_be_bytes()); // length + buf.extend_from_slice(&MAGIC_COOKIE_BYTES); + buf.extend_from_slice(&req.transaction_id); + + // REALM (0x0014) + let realm_bytes = realm.as_bytes(); + buf.extend_from_slice(&0x0014u16.to_be_bytes()); + buf.extend_from_slice(&(realm_bytes.len() as u16).to_be_bytes()); + buf.extend_from_slice(realm_bytes); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0]); } + + // NONCE (0x0015) + let nonce_bytes = nonce.as_bytes(); + buf.extend_from_slice(&0x0015u16.to_be_bytes()); + buf.extend_from_slice(&(nonce_bytes.len() as u16).to_be_bytes()); + buf.extend_from_slice(nonce_bytes); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0]); } + + // Update length + let total_len = (buf.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + buf[2] = len_bytes[0]; + buf[3] = len_bytes[1]; + + buf.to_vec() +} + +/// Find MESSAGE-INTEGRITY attribute (ATTR_MESSAGE_INTEGRITY) if present +pub fn find_message_integrity(msg: &StunMessage) -> Option<&StunAttribute> { + msg.attributes.iter().find(|a| a.typ == ATTR_MESSAGE_INTEGRITY) +} + +/// Validate MESSAGE-INTEGRITY using provided key (password). Returns true if valid. +/// Note: This is a simplified validator that assumes the MESSAGE-INTEGRITY attribute exists and +/// that the message bytes passed are the full STUN message (including attributes). +pub fn validate_message_integrity(msg: &StunMessage, key: &str) -> bool { + if let Some(mi) = find_message_integrity(msg) { + // MESSAGE-INTEGRITY attribute value is 20 bytes (HMAC-SHA1) + if mi.value.len() != 20 { return false; } + // Compute HMAC over the message up to (but excluding) MESSAGE-INTEGRITY attribute header and value + let mi_attr_start = mi.offset; // offset points to attribute header + let msg_slice = &msg.raw[..mi_attr_start]; + let computed = crate::stun::compute_message_integrity(key, msg_slice); + // compare first 20 bytes + return &computed[..20] == mi.value.as_slice(); + } + false +} + +/// Build a simple success (200) response echoing transaction id +pub fn build_success_response(req: &StunHeader) -> Vec { + use bytes::BytesMut; + let mut buf = BytesMut::new(); + let msg_type: u16 = RESP_BINDING_SUCCESS; // Binding success response (example) + buf.extend_from_slice(&msg_type.to_be_bytes()); + buf.extend_from_slice(&0u16.to_be_bytes()); + buf.extend_from_slice(&MAGIC_COOKIE_BYTES); + buf.extend_from_slice(&req.transaction_id); + let total_len = (buf.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + buf[2] = len_bytes[0]; + buf[3] = len_bytes[1]; + buf.to_vec() +} + +/// Compute STUN fingerprint (XOR-32 of CRC32) +pub fn compute_fingerprint(msg: &[u8]) -> u32 { + use crc32fast::Hasher; + let mut hasher = Hasher::new(); + hasher.update(msg); + let crc = hasher.finalize(); + crc ^ 0x5354554e +} + +/// Compute MESSAGE-INTEGRITY (HMAC-SHA1) over the message +pub fn compute_message_integrity(key: &str, msg: &[u8]) -> Vec { + use hmac::{Hmac, Mac}; + use sha1::Sha1; + type HmacSha1 = Hmac; + let mut mac = HmacSha1::new_from_slice(key.as_bytes()).expect("HMAC key"); + mac.update(msg); + mac.finalize().into_bytes().to_vec() +} + +/// STUN/TURN attribute type for XOR-RELAYED-ADDRESS per RFC5766 +/// (use ATTR_XOR_RELAYED_ADDRESS from crate::constants) +// no-op; refer to constants::ATTR_XOR_RELAYED_ADDRESS where needed + +/// Encode an IPv4 SocketAddr into XOR-RELAYED-ADDRESS attribute value. +/// Format (per RFC5389/RFC5766): 1 byte family, 2 byte xport, 4 byte xaddr for IPv4 +pub fn encode_xor_relayed_address(addr: &std::net::SocketAddr, _trans_id: &[u8;12]) -> Vec { + use std::net::IpAddr; + let mut out = Vec::new(); + match addr.ip() { + IpAddr::V4(v4) => { + out.push(0); // first 8 bits zero per spec + out.push(0x01); // family: 0x01 for IPv4 + // xport = port ^ (magic_cookie >> 16) + let port = addr.port(); + let xport = (port ^ ((MAGIC_COOKIE_U32 >> 16) as u16)) as u16; + out.extend_from_slice(&xport.to_be_bytes()); + // xaddr = ipv4 ^ magic_cookie + let octets = v4.octets(); + let cookie_bytes = MAGIC_COOKIE_BYTES; + for i in 0..4 { out.push(octets[i] ^ cookie_bytes[i]); } + } + IpAddr::V6(_v6) => { + // For now, we don't support IPv6 in this MVP implementation + // Return an empty vec to indicate unsupported + } + } + out +} + +/// Decode XOR-RELAYED-ADDRESS attribute value into SocketAddr (IPv4 only) +pub fn decode_xor_relayed_address(value: &[u8], _trans_id: &[u8;12]) -> Option { + if value.len() < 8 { return None; } + if value[1] != 0x01 { return None; } // not IPv4 + let xport = u16::from_be_bytes([value[2], value[3]]); + let port = xport ^ ((MAGIC_COOKIE_U32 >> 16) as u16); + let cookie_bytes = MAGIC_COOKIE_BYTES; + let mut ipb = [0u8;4]; + for i in 0..4 { ipb[i] = value[4 + i] ^ cookie_bytes[i]; } + let ip = std::net::Ipv4Addr::from(ipb); + Some(std::net::SocketAddr::new(std::net::IpAddr::V4(ip), port)) +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_minimal_binding() { + // Build a minimal STUN Binding request with empty attributes + let mut b = Vec::new(); + b.extend_from_slice(&METHOD_BINDING.to_be_bytes()); // Binding Request + b.extend_from_slice(&0u16.to_be_bytes()); // length + b.extend_from_slice(&MAGIC_COOKIE_BYTES); + let trans = [1u8; 12]; + b.extend_from_slice(&trans); + let msg = parse_message(&b).expect("parse"); + assert_eq!(msg.header.msg_type, METHOD_BINDING); + assert_eq!(msg.header.transaction_id, trans); + assert!(msg.attributes.is_empty()); + } + + #[test] + fn build_401_roundtrip() { + let req = StunHeader { msg_type: METHOD_BINDING, length: 0, cookie: MAGIC_COOKIE_U32, transaction_id: [2u8;12] }; + let out = build_401_response(&req, "realm", "nonce", 401); + // parse back should succeed + let parsed = parse_message(&out).expect("parse resp"); + assert!(!parsed.attributes.is_empty()); + } + + #[test] + fn message_integrity_valid_and_invalid() { + use bytes::BytesMut; + + let username = "alice"; + let password = "secret"; // used directly as HMAC key in this MVP + + // Build message: Binding Request + USERNAME attribute + MESSAGE-INTEGRITY placeholder + let mut buf = BytesMut::new(); + buf.extend_from_slice(&METHOD_BINDING.to_be_bytes()); // Binding Request + buf.extend_from_slice(&0u16.to_be_bytes()); // length placeholder + buf.extend_from_slice(&0x2112A442u32.to_be_bytes()); + let trans = [9u8; 12]; + buf.extend_from_slice(&trans); + + // USERNAME (ATTR_USERNAME) + let uname_bytes = username.as_bytes(); + buf.extend_from_slice(&ATTR_USERNAME.to_be_bytes()); + buf.extend_from_slice(&(uname_bytes.len() as u16).to_be_bytes()); + buf.extend_from_slice(uname_bytes); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); } + + // MESSAGE-INTEGRITY placeholder (0x0008) length 20 + let mi_attr_offset = buf.len(); + buf.extend_from_slice(&ATTR_MESSAGE_INTEGRITY.to_be_bytes()); + buf.extend_from_slice(&(20u16).to_be_bytes()); + let mi_val_pos = buf.len(); + buf.extend_from_slice(&[0u8;20]); + while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); } + + // Fix length + let total_len = (buf.len() - 20) as u16; + let len_bytes = total_len.to_be_bytes(); + buf[2] = len_bytes[0]; + buf[3] = len_bytes[1]; + + // Compute HMAC over message up to MI attribute header (mi_attr_offset) + let hmac = compute_message_integrity(password, &buf[..mi_attr_offset]); + // place first 20 bytes into mi value + for i in 0..20 { buf[mi_val_pos + i] = hmac[i]; } + + // Parse and validate + let parsed = parse_message(&buf).expect("parsed"); + assert!(validate_message_integrity(&parsed, password)); + + // tamper: change one byte -> invalid + let mut tampered = buf.to_vec(); + tampered[10] ^= 0xFF; + let parsed2 = parse_message(&tampered).expect("parsed2"); + assert!(!validate_message_integrity(&parsed2, password)); + } +} diff --git a/src/traits/credential_store.rs b/src/traits/credential_store.rs new file mode 100644 index 0000000..2b3d734 --- /dev/null +++ b/src/traits/credential_store.rs @@ -0,0 +1,8 @@ +use async_trait::async_trait; + +/// CredentialStore trait - async abstraction for credential backends +#[async_trait] +pub trait CredentialStore: Send + Sync + 'static { + /// Look up a password for a username. Returns None if user not found. + async fn get_password(&self, username: &str) -> Option; +} diff --git a/src/traits/mod.rs b/src/traits/mod.rs new file mode 100644 index 0000000..3ac5e6d --- /dev/null +++ b/src/traits/mod.rs @@ -0,0 +1,3 @@ +pub mod credential_store; + +pub use credential_store::CredentialStore;