programing

조각화없이 보낼 수있는 가장 큰 UDP 패킷을 찾는 방법은 무엇입니까?

minecode 2021. 1. 16. 09:27
반응형

조각화없이 보낼 수있는 가장 큰 UDP 패킷을 찾는 방법은 무엇입니까?


다른 컴퓨터로 보낼 수있는 가장 큰 UDP 패킷이 조각화없이 무엇인지 알아야합니다.

이 크기를 일반적으로 MTU (Maximum Transmission Unit)라고합니다. 두 컴퓨터 사이에는 MTU가 다를 수있는 많은 라우터와 모뎀이 있다고 가정합니다.

Windows의 TCP 구현이 경로에서 최대 MTU를 자동으로 찾는다는 것을 읽었습니다.

나는 또한 실험을했고 내 컴퓨터에서 서버까지의 최대 MTU가 57712 바이트 + 헤더라는 것을 알았습니다. 그 이상의 모든 것은 버려졌습니다. 내 컴퓨터가 LAN에 있는데 MTU가 약 1500 바이트 여야하지 않습니까?


다음은 귀하의 질문에 직접 답변하지는 않지만 흥미로울 수 있습니다. IP 패킷을 분해 / 재 조립할 수 있으므로 기본 미디어 (예 : 1500 바이트 이더넷)의 제한보다 큽니다. GRE 및 IPSEC를 사용하여 IP 조각화, MTU, MSS 및 PMTUD 문제 해결


이 주제에 대한 추가 정보 :

  • Re : UDP 조각화 는 MTU를 발견하기 위해 UDP 대신 ICMP를 사용해야한다고 말합니다.
  • 경로 MTU 검색에 따르면 TCP 연결에 ICMP를 통한 암시 적 MTU 협상이 포함될 수 있음

저는 Windows에서 API를 통해 ICMP를 생성하는 방법을 모릅니다. 한때 그러한 API가 제안되었고 사람들이 서비스 거부 기능을 구현하는 소프트웨어를 쉽게 작성할 수 있다고 주장했기 때문에 논란이되었습니다. ICMP 메시지.

아니, 그것이 보이는 되어 예를 들어 참조 : 구현 Winsock을 프로그래머 자주 묻는 질문 예 : 핑 : 원시 소켓 방법 .

따라서 MTU를 검색하려면 '조각화하지 않음'플래그를 사용하여 ping 패킷을 생성하십시오.

아마도 이것보다 쉬운 API가 있을지 모르겠습니다. 그러나 나는 당신이 기본 프로토콜을 이해하기를 바랍니다.


이전의 모든 답변 외에도 클래식을 인용합니다 .

IPv4 및 IPv6는 최소 리 어셈블리 버퍼 크기를 정의 합니다. 이는 모든 구현에서 지원해야하는 최소 데이터 그램 크기입니다. IPv4의 경우 576 바이트입니다. IPv6는이를 1,280 바이트로 올립니다.


이것은 공용 인터넷을 통해 작업하고 교환의 한쪽 만 제어하는 ​​경우 데이터 그램 크기를 576 미만으로 제한하려는 것을 의미합니다. 이것이 대부분의 표준 UDP 기반 프로토콜이하는 일입니다.

또한 PMTU는 경로의 동적 속성입니다. 이것은 TCP가 당신을 위해 다루는 것 중 하나입니다. 많은 시퀀싱, 타이밍 및 재전송 논리를 다시 구현할 준비가되지 않은 경우 중요한 네트워킹에 TCP를 사용하십시오. 벤치 마크, 테스트, 프로필, 즉 TCP가 병목 임을 증명 한 다음 UDP를 고려하십시오.


이것은 저에게 흥미로운 주제입니다. UDP를 통해 실제 인터넷에 덩어리가 많은 UDP 데이터를 전달할 때 몇 가지 실용적인 결과가 흥미로울 수 있으며 초당 1 패킷의 전송 속도로 최대 약 2K의 최소 패킷 손실로 데이터가 계속 증가합니다. 이 과정에서 문제가 발생하기 시작하지만 정기적으로 우리는 어려움없이 1600 바이트 이상의 패킷을 전달했습니다. 이것은 GPRS 모바일 네트워크와 전 세계 WAN을 통해 이루어집니다. 신호가 안정적이라고 가정하면 ~ 1K에서 패킷 손실이 적습니다.

흥미롭게도 이상한 패킷이 아니라 종종 몇 초 동안 패킷이 뭉쳐지는 경우가 있습니다. 이것이 아마도 VoIP 통화가 때때로 중단되는 이유 일 것입니다.


자신의 MTU는 레지스트리 에서 사용할 수 있지만 실제로 MTU는 컴퓨터와 대상 사이의 경로에서 가장 작은 MTU로 이동합니다. 둘 다 변수이며 경험적으로 만 결정할 수 있습니다. 이를 결정하는 방법을 보여주는 많은 RFC 가 있습니다.

네트워크 하드웨어는 일반적으로 동종이거나 적어도 중앙에서 관리되기 때문에 LAN은 내부적으로 매우 큰 MTU 값을 가질 수 있습니다.


UDP 애플리케이션의 경우 IP 조각화 또는 패킷 손실을 방지하려면 종단 간 MTU를 직접 처리해야합니다. 모든 애플리케이션에 권장되는 접근 방식은 PMTU를 사용하여 최대 데이터 그램을 선택하거나 데이터 그램 <최소 PMTU를 전송하는 것입니다.

https://tools.ietf.org/html/rfc5405#section-3.2

응용 프로그램 설계자를위한 유니 캐스트 UDP 사용 지침 "PMTU를 초과하는 데이터 그램을 보내면 안됩니다. PMTU를 검색하거나 최소 PMTU 미만의 데이터 그램을 보내야합니다.

Windows는 기본 소켓 옵션 인터페이스를 통해 PMTU 정보에 대한 설정 및 액세스에 나타납니다.

PMTU 검색이 IP_MTU_DISCOVER를 통해 켜져 있는지 확인하고 IP_MTU를 통해 MTU를 읽을 수 있습니다.

https://docs.microsoft.com/en-us/windows/desktop/winsock/ipproto-ip-socket-options


다음은 Path MTU 문제를 확인하기 위해 작성한 Windows PowerShell의 일부입니다. (일반적인 기술은 다른 프로그래밍 언어로 구현하기에는 그리 어렵지 않습니다.) 많은 방화벽과 라우터가 더 잘 모르는 사람들이 모든 ICMP를 삭제하도록 구성되어 있습니다. Path MTU Discovery는 Do n't Fragment가 설정된 패킷을 전송 한 것에 대한 응답으로 Fragementation Needed가 설정된 ICMP Destination Unreachable 메시지를 수신 할 수 있는지 여부에 따라 다릅니다. 해결 IPv4의 분열, MTU, MSS, 및 GRE와 PMTUD 문제 및 IPsec은 실제로 어떻게 검색 작품을 설명하는 정말 좋은 일을한다.

function Test-IPAddressOrName($ipAddressOrName)
{
    $ipaddress = $null
    $isValidIPAddressOrName = [ipaddress]::TryParse($ipAddressOrName, [ref] $ipaddress)

    if ($isValidIPAddressOrName -eq $false)
    {
        $hasResolveDnsCommand = $null -ne (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)
        if ($hasResolveDnsCommand -eq $true)
        {
            $dnsResult = Resolve-DnsName -DnsOnly -Name $ipAddressOrName -ErrorAction SilentlyContinue
            $isValidIPAddressOrName = $null -ne $dnsResult
        }
    }

    return $isValidIPAddressOrName
}

function Get-NameAndIPAddress($ipAddressOrName)
{
    $hasResolveDnsCommand = $null -ne (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)

    $ipAddress = $null
    $validIPAddress = [ipaddress]::TryParse($ipAddressOrName, [ref] $ipAddress)
    $nameAndIp = [PSCustomObject] @{ 'Name' = $null; 'IPAddress' = $null }

    if ($validIPAddress -eq $false)
    {
        if ($hasResolveDnsCommand -eq $true)
        {
            $dnsResult = Resolve-DnsName -DnsOnly $ipAddressOrName -Type A -ErrorAction SilentlyContinue

            if ($null -ne $dnsResult -and $dnsResult.QueryType -eq 'A')
            {
                $nameAndIp.Name = $dnsResult.Name
                $nameAndIp.IPAddress = $dnsResult.IPAddress
            }
            else
            {
                Write-Error "The name $($ipAddressOrName) could not be resolved."
                $nameAndIp = $null
            }
        }
        else
        {
            Write-Warning "Resolve-DnsName not present. DNS resolution check skipped."
        }
    }
    else
    {
        $nameAndIp.IPAddress = $ipAddress

        if ($hasResolveDnsCommand -eq $true)
        {
            $dnsResult = Resolve-DnsName -DnsOnly $ipAddress -Type PTR -ErrorAction SilentlyContinue

            if ($null -ne $dnsResult -and $dnsResult.QueryType -eq 'PTR')
            {
                $nameAndIp.Name = $dnsResult.NameHost
            }
        }
    }

    return $nameAndIp
}

<#
    .Synopsis
    Performs a series of pings (ICMP echo requests) with Don't Fragment specified to discover the path MTU (Maximum Transmission Unit).

    .Description
    Performs a series of pings with Don't Fragment specified to discover the path MTU (Maximum Transmission Unit). An ICMP echo request 
    is sent with a random payload with a payload length specified by the PayloadBytesMinimun. ICMP echo requests of increasing size are 
    sent until a ping response status other than Success is received. If the response status is PackeTooBig, the last successful packet 
    length is returned as a reliable MTU; otherwise, if the respone status is TimedOut, the same size packet is retried up to the number 
    of retries specified. If all of the retries have been exhausted with a response status of TimedOut, the last successful packet 
    length is returned as the assumed MTU.

    .Parameter UseDefaultGateway
    If UseDefaultGateway is specified the default gateway reported by the network interface is used as the destination host.

    .Parameter DestinationHost
    The IP Address or valid fully qualified DNS name of the destination host.

    .Parameter InitialTimeout
    The number of milliseconds to wait for an ICMP echo reply. Internally, this is doubled each time a retry occurs.

    .Parameter Retries
    The number of times to try the ping in the event that no reply is recieved before the timeout.

    .Parameter PayloadBytesMinimum
    The minimum number of bytes in the payload to use. The minimum MTU for IPv4 is 68 bytes; however, in practice, it's extremely rare 
    to see an MTU size less than 576 bytes so the default value is 548 bytes (576 bytes total packet size minus an ICMP header of 28 
    bytes).

    .Parameter PayloadBytesMaximum
    The maximum number of bytes in the payload to use. An IPv4 MTU for jumbo frames is 9000 bytes. The default value is 8973 bytes (9001 
    bytes total packet size, which is 1 byte larger than the maximum IPv4 MTU for a jumbo frame, minus an ICMP header of 28 bytes).

    .Example
    Discover-PathMTU -UseDefaultGateway

    .Example
    Discover-PathMTU -DestinationHost '192.168.1.1'

    .Example
    Discover-PathMTU -DestinationHost 'www.google.com'
#>
function Discover-PathMtu
{
    [CmdletBinding(SupportsShouldProcess = $false)]
    param
    (
        [Parameter(Mandatory = $true, ParameterSetName = 'DefaultGateway')]
        [switch] $UseDefaultGateway,

        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ParameterSetName = 'IPAddressOrName')]
        [ValidateScript({ Test-IPAddressOrName $_ })]
        [string] $DestinationHost,

        [Parameter(ParameterSetName = 'IPAddressOrName')]
        [Parameter(ParameterSetName = 'DefaultGateway')]
        [int] $InitialTimeout = 3000,

        [Parameter(ParameterSetName = 'IPAddressOrName')]
        [Parameter(ParameterSetName = 'DefaultGateway')]
        [int] $Retries = 3,

        [Parameter(ParameterSetName = 'IPAddressOrName')]
        [Parameter(ParameterSetName = 'DefaultGateway')]
        $PayloadBytesMinimum = 548,

        [Parameter(ParameterSetName = 'IPAddressOrName')]
        [Parameter(ParameterSetName = 'DefaultGateway')]
        $PayloadBytesMaximum = 8973
    )

    begin
    {
        $ipConfiguration = Get-NetIPConfiguration -Detailed | ?{ $_.NetProfile.Ipv4Connectivity -eq 'Internet' -and $_.NetAdapter.Status -eq 'Up' } | Sort { $_.IPv4DefaultGateway.InterfaceMetric } | Select -First 1
        $gatewayIPAddress = $ipConfiguration.IPv4DefaultGateway.NextHop

        $pingOptions = New-Object System.Net.NetworkInformation.PingOptions
        $pingOptions.DontFragment = $true
        $pinger = New-Object System.Net.NetworkInformation.Ping

        $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
    }

    process
    {
        $pingIpAddress = $null

        if ($UseDefaultGateway -eq $true)
        {
            $DestinationHost = $gatewayIPAddress
        }

        $nameAndIP = Get-NameAndIPAddress $DestinationHost

        if ($null -ne $nameAndIP)
        {
            Write-Host "Performing Path MTU discovery for $($nameAndIP.Name) $($nameAndIP.IPAddress)..."

            $pingReply = $null
            $payloadLength = $PayloadBytesMinimum
            $workingPingTimeout = $InitialTimeout

            do
            {
                $payloadLength++

                # Use a random payload to prevent compression in the path from potentially causing a false MTU report.
                [byte[]] $payloadBuffer = (,0x00 * $payloadLength)
                $rng.GetBytes($payloadBuffer)

                $pingCount = 1

                do
                {
                    $pingReply = $pinger.Send($nameAndIP.IPAddress, $workingPingTimeout, $payloadBuffer, $pingOptions)

                    if ($pingReply.Status -notin 'Success', 'PacketTooBig', 'TimedOut')
                    {
                        Write-Warning "An unexpected ping reply status, $($pingReply.Status), was received in $($pingReply.RoundtripTime) milliseconds on attempt $($pingCount)."
                    }
                    elseif ($pingReply.Status -eq 'TimedOut')
                    {
                        Write-Warning "The ping request timed out while testing a packet of size $($payloadLength + 28) using a timeout value of $($workingPingTimeout) milliseconds on attempt $($pingCount)."
                        $workingPingTimeout = $workingPingTimeout * 2
                    }
                    else
                    {
                        Write-Verbose "Testing packet of size $($payloadLength + 28). The reply was $($pingReply.Status) and was received in $($pingReply.RoundtripTime) milliseconds on attempt $($pingCount)."
                        $workingPingTimeout = $InitialTimeout
                    }

                    Sleep -Milliseconds 10

                    $pingCount++
                } while ($pingReply.Status -eq 'TimedOut' -and $pingCount -le $Retries)
            } while ($payloadLength -lt $PayloadBytesMaximum -and $pingReply -ne $null -and $pingReply.Status -eq 'Success')

            if ($pingReply.Status -eq 'PacketTooBig')
            {
                Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27)."
            }
            elseif ($pingReply.Status -eq 'TimedOut')
            {
                Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27), but may not be reliable because the packet appears to have been discarded."    
            }
            else
            {
                Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27), but may not be reliable, due to an unexpected ping reply status."    
            }

            return $payloadLength + 27
        }
        else
        {
            Write-Error "The name $($DestinationHost) could not be resolved. No Path MTU discovery will be performed."
        }
    }

    end
    {
        if ($null -ne $pinger)
        {
            $pinger.Dispose()
        }

        if ($null -ne $rng)
        {
            $rng.Dispose()
        }
    }
}

참조 URL : https://stackoverflow.com/questions/900697/how-to-find-the-largest-udp-packet-i-can-send-without-fragmenting

반응형