OpenXbox / xcloud-python

21 stars 2 forks source link

ICE/STUN: Negotiation #2

Open tuxuser opened 3 years ago

tuxuser commented 3 years ago

Problem

ICE (Interactive Connectivity Establishment) / STUN is used to negotiate communication-channel between NAT'd hosts. Its currently only used for xhomestreaming. The initial ICE-message comes from the client (mobile device - iOS/Android) to the cloud.

Questions:

Current version of assembling the ICE request

https://github.com/tuxuser/xcloud/blob/8295d2c86bf8ece56dbbd02c1f749a4426955bcb/ice.py#L26-L37

You can test what the used library produces when gathering local candidates with following snippet:

import asyncio
from aiortc import RTCIceGatherer

async def main():
    gatherer = RTCIceGatherer()

    await gatherer.gather()
    candidates = gatherer.getLocalCandidates()
    params = gatherer.getLocalParameters()

    print(':: Candidates')
    for candidate in candidates:
        print(candidate)

    print(':: Params')
    print(params)

asyncio.run(main())

Local IPs: 10.0.0.102 (Wireless), 10.0.0.246 (Wired) Public IP: 126.242.118.111

Output:

:: Candidates
RTCIceCandidate(component=1, foundation='d175634b4f0f6f112c7c1cc9ad15ec68', ip='10.0.0.102', port=58503, priority=2130706431, protocol='udp', type='host', relatedAddress=None, relatedPort=None, sdpMid=None, sdpMLineIndex=None, tcpType=None)
RTCIceCandidate(component=1, foundation='c03547823954444e207cb7cb72c3c97c', ip='10.0.0.246', port=55610, priority=2130706431, protocol='udp', type='host', relatedAddress=None, relatedPort=None, sdpMid=None, sdpMLineIndex=None, tcpType=None)
RTCIceCandidate(component=1, foundation='b08d047b90595fc82469f8b2b3913eaf', ip='126.242.118.111', port=55610, priority=1694498815, protocol='udp', type='srflx', relatedAddress='10.0.0.246', relatedPort=55610, sdpMid=None, sdpMLineIndex=None, tcpType=None)
RTCIceCandidate(component=1, foundation='7eb039734c8997056a4537b2821f17f2', ip='126.242.118.111', port=58503, priority=1694498815, protocol='udp', type='srflx', relatedAddress='10.0.0.102', relatedPort=58503, sdpMid=None, sdpMLineIndex=None, tcpType=None)
:: Params
RTCIceParameters(usernameFragment='Goil', password='LCeehS7T9xJ0uYOBtvJbXz', iceLite=False)

Real / sample data

NOTE: The actual JSON post data is in a very fucked format, so I converted it for better visibility.

Original sample request, 1:1 as sent:

{
    "candidates": "{\n    \"Full\": \"1\",\n    \"PacingMs\": \"50\",\n    \"Version\": \"1\",\n    \"Candidates\": {\n        \"count\": \"2\",\n        \"0\": {\n            \"transportAddress\": \"10.0.0.187:46274\",\n            \"baseAddress\": \"10.0.0.187:46274\",\n            \"serverAddress\": \"\",\n            \"ipv6\": \"0\",\n            \"type\": \"0\",\n            \"addressType\": \"3\",\n            \"priority\": \"2130706175\",\n            \"foundation\": \"1047782621\",\n            \"transport\": \"udp\"\n        },\n        \"1\": {\n            \"transportAddress\": \"[2001:0:338c:24f4:3405:17fd:a21d:47d7]:59394\",\n            \"baseAddress\": \"teredo\",\n            \"serverAddress\": \"\",\n            \"ipv6\": \"1\",\n            \"type\": \"4\",\n            \"addressType\": \"0\",\n            \"priority\": \"2130706431\",\n            \"foundation\": \"1337598143\",\n            \"transport\": \"udp\"\n        }\n    },\n    \"Username\": \"F+R3n0qOTvc=\",\n    \"Password\": \"ciypiKgGwlnWDQ8nqx3oFy3xs6eRHo4WpVDoFNjWyiM=\"\n}\n"
}

iOS

Request

POST https://uks.gssv-play-prodxhome.xboxlive.com/v4/sessions/home/<SESSION_GUID>/ice

{
    "candidates": {
        "Full": "1",
        "PacingMs": "50",
        "Version": "1",
        "Candidates": {
            "count": "7",
            "0": {
                "transportAddress": "[fe80::211:2daf:bbc4:7c6d]:59485",
                "baseAddress": "[fe80::211:2daf:bbc4:7c6d%utun1]:59485",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "4",
                "priority": "2130704895",
                "foundation": "1966258098",
                "transport": "udp"
            },
            "1": {
                "transportAddress": "[fe80::f7d9:41:3b02:e963]:54748",
                "baseAddress": "[fe80::f7d9:41:3b02:e963%utun0]:54748",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "4",
                "priority": "2130705151",
                "foundation": "1623794664",
                "transport": "udp"
            },
            "2": {
                "transportAddress": "[fe80::e8e2:a3ff:fe47:cf82]:57121",
                "baseAddress": "[fe80::e8e2:a3ff:fe47:cf82%awdl0]:57121",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "4",
                "priority": "2130705407",
                "foundation": "4238851165",
                "transport": "udp"
            },
            "3": {
                "transportAddress": "[fe80::e8e2:a3ff:fe47:cf82]:50840",
                "baseAddress": "[fe80::e8e2:a3ff:fe47:cf82%llw0]:50840",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "4",
                "priority": "2130705663",
                "foundation": "193038242",
                "transport": "udp"
            },
            "4": {
                "transportAddress": "10.0.0.210:64864",
                "baseAddress": "10.0.0.210:64864",
                "serverAddress": "",
                "ipv6": "0",
                "type": "0",
                "addressType": "3",
                "priority": "2130705919",
                "foundation": "8449565",
                "transport": "udp"
            },
            "5": {
                "transportAddress": "[fe80::1]:60576",
                "baseAddress": "[fe80::1%lo0]:60576",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "4",
                "priority": "2130706175",
                "foundation": "1535104454",
                "transport": "udp"
            },
            "6": {
                "transportAddress": "[2001:0:338c:24f4:429:211e:a21d:47d7]:57057",
                "baseAddress": "teredo",
                "serverAddress": "",
                "ipv6": "1",
                "type": "4",
                "addressType": "0",
                "priority": "2130706431",
                "foundation": "2234788496",
                "transport": "udp"
            }
        },
        "Username": "u1hWGHuvhTs=",
        "Password": "XFBjMQwX3CJxtHs1oj8WbzlT74I+P4gJWbh\\/OJrETgo="
    }
}

Response

GET https://uks.gssv-play-prodxhome.xboxlive.com/v4/sessions/home/<SESSION_GUID>/ice

{
    "candidates": {
        "Full": "1",
        "PacingMs": "50",
        "Version": "1",
        "Candidates": {
            "count": "3",
            "0": {
                "transportAddress": "10.0.0.174:51068",
                "baseAddress": "10.0.0.174:51068",
                "serverAddress": "",
                "ipv6": "0",
                "type": "0",
                "addressType": "3",
                "priority": "2130705919",
                "foundation": "3475377771",
                "transport": "udp"
            },
            "1": {
                "transportAddress": "[2001:0:338c:24f4:456:f3fd:a21d:47d7]:51069",
                "baseAddress": "[2001:0:338c:24f4:456:f3fd:a21d:47d7]:51069",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "0",
                "priority": "2130706175",
                "foundation": "1346576940",
                "transport": "udp"
            },
            "2": {
                "transportAddress": "[fe80::456:f3fd:a21d:47d7]:51070",
                "baseAddress": "[fe80::456:f3fd:a21d:47d7%6]:51070",
                "serverAddress": "",
                "ipv6": "1",
                "type": "0",
                "addressType": "4",
                "priority": "2130706431",
                "foundation": "2239954977",
                "transport": "udp"
            }
        },
        "Username": "K9rfTAAHfMI=",
        "Password": "g3IuMXEcLVau\\/2QhQq6MvpsOqGBJHJ3T3+tg68p97fs="
    }
}

Android

Request

POST https://uks.gssv-play-prodxhome.xboxlive.com/v4/sessions/home/<SESSION_GUID>/ice

{
    "candidates": {
        "Candidates": {
            "0": {
                "addressType": "3",
                "baseAddress": "10.0.0.187:46274",
                "foundation": "1047782621",
                "ipv6": "0",
                "priority": "2130706175",
                "serverAddress": "",
                "transport": "udp",
                "transportAddress": "10.0.0.187:46274",
                "type": "0"
            },
            "1": {
                "addressType": "0",
                "baseAddress": "teredo",
                "foundation": "1337598143",
                "ipv6": "1",
                "priority": "2130706431",
                "serverAddress": "",
                "transport": "udp",
                "transportAddress": "[2001:0:338c:24f4:3405:17fd:a21d:47d7]:59394",
                "type": "4"
            },
            "count": "2"
        },
        "Full": "1",
        "PacingMs": "50",
        "Password": "ciypiKgGwlnWDQ8nqx3oFy3xs6eRHo4WpVDoFNjWyiM=",
        "Username": "F+R3n0qOTvc=",
        "Version": "1"
    }
}

Response

GET https://uks.gssv-play-prodxhome.xboxlive.com/v4/sessions/home/<SESSION_GUID>/ice

{
    "candidates": {
        "Candidates": {
            "0": {
                "addressType": "3",
                "baseAddress": "10.0.0.174:56974",
                "foundation": "1251832755",
                "ipv6": "0",
                "priority": "2130705919",
                "serverAddress": "",
                "transport": "udp",
                "transportAddress": "10.0.0.174:56974",
                "type": "0"
            },
            "1": {
                "addressType": "0",
                "baseAddress": "[2001:0:338c:24f4:20c1:f3fd:a21d:47d7]:56975",
                "foundation": "491644152",
                "ipv6": "1",
                "priority": "2130706175",
                "serverAddress": "",
                "transport": "udp",
                "transportAddress": "[2001:0:338c:24f4:20c1:f3fd:a21d:47d7]:56975",
                "type": "0"
            },
            "2": {
                "addressType": "4",
                "baseAddress": "[fe80::20c1:f3fd:a21d:47d7%6]:56976",
                "foundation": "3489845490",
                "ipv6": "1",
                "priority": "2130706431",
                "serverAddress": "",
                "transport": "udp",
                "transportAddress": "[fe80::20c1:f3fd:a21d:47d7]:56976",
                "type": "0"
            },
            "count": "3"
        },
        "Full": "1",
        "PacingMs": "50",
        "Password": "lNj2y+Q3Jkec7SlUcsOwaAHOS5Fad4gKxmmHBumPnTo=",
        "Username": "nxhPDLwFKc0=",
        "Version": "1"
    }
}

Libraries

aiortc aioice (used by aiortc)

Specs

RFC 4380 Teredo: Tunneling IPv6 over UDP through Network Address Translations (NATs) RFC 5245 Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal for Offer/Answer Protocols RFC 5839 Session Traversal Utilities for NAT (STUN) RFC 5991 Teredo Security Updates RFC 6081 Teredo Extensions RFC 8445 Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal

akahmet commented 3 years ago

Is Teredo involved for gathering that info? Nope, Probably you are using a tunel for IPV6.

tuxuser commented 3 years ago

Nope, Probably you are using a tunel for IPV6.

True, but even non-tunneled connection have a few Teredo packets ;)

For parsing of STUN packets, we can use aioice's code: https://github.com/jlaine/aioice/blob/39d7b642af0b9e95c092a72c0702a92cd5d98ca0/src/aioice/stun.py#L310