06.05. ICMP nesasniedzamā porta kļūda

Pēdējais mainījis Administrator 2011-06-06 17:16

06.05. ICMP nesasniedzamā porta kļūda

Iepriekšējās divas nodaļas aplūkoja ICMP pieprasījumu ziņojumus - adreses maskas un laikspiedoga pieprasījumus un atbildes. Tagad aplūkosim, kādu papildu informāciju atgriež #term("nesasniedzamā porta ziņojumu", "port_unreachable_message") ICMP kļūdas ziņojums, kas ir ICMP nesasniedzamā galamērķa ziņojuma apakškods. Mēs šo skatīsimies, izmantojot #term("UDP", "User_Datagram_Protocol") (11.nodaļa).

Viens no UDP likumiem ir, ka, saņemot UDP datagrammu, ja adresāta ports neatbilst kāda procesa lietotam porta numuram, tad UDP slānis atbild ar ICMP nesasniedzamā porta kļūdu. Varam izraisīt nesasniedzamā porta kļūdu, izmantojot #term("TFTP", "Trivial_File_Transfer_Protocol") klientu (TFTP aprakstīsim 15.nodaļā).

Labi zināmais UDP porta numurs TFTP serverim ir 69. Bet vairums TFTP klientu programmas ļauj mums norādīt citu portu, izmantojot 'connect' komandu. Mēs to izmantojam, lai norādītu portu 8888:

bsdi % tftp
tftp> connect svr4 8888     (norāda mītni un porta numuru)
tftp> get temp.foo          (mēģina savākt failu)
Transfer timed out.         (pēc apm. 15 sekundēm)
tftp> quit

Komanda 'connect' noglabā mītnes vārdu, ar ko sazināties un porta numuru uz šīs mītnes vēlākai 'get' komandas ievadei. Pēc 'get' komandas ievades UDP datagrammu nosūta servera svr4 portam 8888. #picref("f_6_8.gif", "6.8.attēls") parāda notiekošo tcpdump pakešu apmaiņas izvadi.

Pirms UDP datagrammu var nosūtīt uz svr4, nosūta ARP pieprasījumu, lai noskaidrotu tā aparatūras adresi (1.rindiņa). ARTP atbilde (2.rindiņa) tiek atgriezta, un pēc tam sūta UDP datagrammu (3.rindiņa). Esam atstājuši šo #term("ARP", "Address_Resolution_Protocol") pieprasījumu un atbildi tcpdump izvadē, lai atgādinātu, ka šāda komunikācija var būt nepieciešama pirms izsūtīt pirmo IP datagrammu no vienas mītnes otrai. Nākošajās izdrukās šo apmaiņu nenorādīsim, ja vien tā nebūs būtiska apspriežamajam tematam.

#pic("f_6_8.gif", "500")
6.8.attēls: ICMP nesasniedzama porta ziņojums, ko ģenerē TFTP pieprasījums

Tūlīt tiek atgriezta ICMP nesasniedzamā porta kļūda (4.rindiņa). Bet TFTP klients, šķiet, ignorē šo ICMP ziņojumu, nosūtot vēl vienu UDP datagrammu apmēram pēc 5 sekundēm (5.rindiņa). Tas turpinās vēl 3 reizes, pirms klients liekas mierā.

Ievērojiet, ka ICMP ziņojumus apmaina pašas mītnes (īpaši nenorādot portu numurus), turpretī ikviena 20-baitu UDP datagramma ir no konkrēta porta (2924) uz konkrētu portu (8888).

Skaitlis 20 katras UDP rindiņas beigās ir datu garums konkrētajā UDP datagrammā. Šajā piemērā 20 ir summa TFTP 2-baitu operācijas kodam (opcode), 9-baitu nosaukumam "temp.foo" (tas beidzas ar nulles baitu), un 9-baitu stringam "netascii" (arī beidzas ar nulles baitu). Sk. #picref("f_15_1.gif", "15.1.attēlu"), lai uzzinātu detaļas par TFTP paketes izkārtojumu.

Ja darbināsim šo pašu piemēru, izmantojot -e opciju tcpdump programmai, redzēsim, precīzu katra ICMP nesasniedzamā porta ziņojuma garumu, kuru atgriež UDP sūtītājam. Šis garums ir 70 baiti un tiek iedalīts kā attēlots #picref("f_6_9.gif", "6.9.attēlā").

#pic("f_6_9.gif", "500")
6.9.attēls: ICMP ziņojums, ko atgriež mūsu "UDP port unreachable" piemērā

Viens no ICMP likumiem ir tāds, ka ICMP kļūdu ziņojumi (sk. pēdējo kolonnu #picref("f_6_3.gif", "6.3.attēlā")) vienmēr iekļauj IP kļūdu ģenerējošās datagrammas sākumposmu (ieskaitot opcijas) un pirmos 8 sākumposmam sekojošos datu baitus. Mūsu piemērā pirmie 8 baiti pēc IP sākumposma satur UDP sākumposmu (#picref("f_11_2.gif", "11.2.attēls")).

Svarīgi zināt, ka UDP sākumposmā ir ietverti avota un galamērķa portu numuri. Šoreiz galamērķa porta numurs (8888) izraisīja ICMP #term("nesasniedzamā porta", "port_unreachable_message") ģenerēšanu. Avota porta numuru (2924) var izmantot sistēma, kura saņems ICMP kļūdu, lai saistītu šo kļūdas ziņojumu ar konkrētu lietotāja procesu (konkrēti šajā gadījumā - #term("TFTP", "Trivial_File_Transfer_Protocol") klientu).

Viens no iemesliem, kādēļ sūta atpakaļ kļūdu izraisījušās IP datagrammas IP sākumposmu ir tas, ka šis IP sākumposms ir tas protokola lauks, kurš ļauj ICMP saprast, kā interpretēt nākamos 8 baitus (konkrēti šajā gadījumā UDP sākumposmu). Kad aplūkojam TCP sākumposmu (#picref("f_17_2.gif", "17.2.attēlu")), redzēsim, ka avota un galamērķa portu numuri ir ietverti pirmajos 8 bitos arī TCP sākumposmam. ICMP nesasniedzamības ziņojumu vispārīgais formāts ir parādīts 6.10.attēlā.

#pic("f_6_10.gif", "500")
6.10.attēls: ICMP nesasniedzamības ziņojums

#picref("f_6_3.gif", "6.3.attēlā") atzīmējām, ka ir 16 dažādi ICMP nesasniedzamības ziņojumi, kuru kodi ir no 0 līdz 15. ICMP #term("nesasniedzamā porta", "port_unreachable_message") kods ir 3. Arī, lai gan #picref("f_6_10.gif", "6.10.attēls") norāda, ka otrajam 32-bitu vārdam ICMP ziņojumā jābūt 0, #term("Ceļa MTU Atrašanas", "Path_MTU_Discovery") mehānisms (2.9.nodaļa?) atļauj maršrutētājam novietot izejošās saskarnes #term("MTU", "maximum_transmission_unit") jaunākajos 16 bitos šai 32-bitu vērtībai, kad kods vienāds ar 4 (ziņojums "nepieciešama fragmentācija, bet ir uzstādīts nefragmentēšanas bits"). Šīs kļūdas piemēru redzēsim 11.6.nodaļā?.

Lai gan ICMP likumi ļauj sistēmai atgriezt vairāk nekā pirmos 8 baitus no kļūdu izraisījušās IP datagrammas datu sadaļas, vairums no Bērklija atvasināto implementāciju atgriež precīzi 8 baitus. Solaris 2.2 sistēmās opcija ip_icmp_return_data_bytes pēc noklusēšanas atgriež pirmos datu sadaļas 64 baitus (E.4.nodaļa?).

tcpdump hronoloģija

Viscaur šajā grāmatā attēlosim tcpdump izvadi hronoloģiskā diagrammā, kā parādīts #picref("f_6_11.gif", "6.11.attēlā").

#pic("f_6_11.gif", "500")
6.11.attēls: Hronoloģija TFTP pieprasījumam uz nederīgu portu

Laiks pieaug, virzoties uz leju un iezīmes attēla kreisajā pusē ir tās pašas laika vērtības, kas mūsu tcpdump izvadē (#picref("f_6_8.gif","6.8.attēlā"). Iezīmes augšā ir mītnes vārdi un portu numuri katrai komunikācijas pusei. Jāņem vērā, ka y koordinātu ass nav gluži proporcionāla laika vērtībām. Kad ir ievērojama laika atstarpe, piemēram pēc katras 5-sekunžu atkalsūtīšanas šajā piemērā, mēs apzīmējam to ar zigzagu abās hronoloģijas pusēs. Kad tiek sūtīti UDP vai TCP dati, mēs šo paketi attēlojam ar biezāku līniju.

Kādēļ TFTP klients turpina #term("atkalsūtīt", "retransmit") pieprasījumu arī pēc ICMP ziņojumu atgriešanas? Te izpaužas tīklu programmēšanas efekts, kurā BSD sistēmas nepaziņo lietotāju procesiem, kuri izmanto UDP, par ICMP ziņojumiem, kas tiek saņemti par attiecīgo #term("soketu", "socket"), ja vien process nav izveidojis savienojumu uz šo soketu. Standartais BSD sistēmā esošais TFTP klients neveido savienojumu, tādēļ arī tas nesaņem ICMP #term("kļūdas paziņojumu", "error_notification").

Var ievērot arī slikto atkalsūtīšanas #term("noildzes", "timeout") algoritmu, ko izmanto šis TFTP klients. Tas pieņem, ka 5 sekundes ir piemērots laiks un atkalsūta katras 5 sekundes, izmantojot kopumā 25 sekundes. Vēlāk redzēsim, ka TCP ir daudz labāks algoritms.

Šis senlaicīgais noildzes un atkalsūtīšanas algoritms, ko lieto TFTP klients, ir aizliegts #term("Mītņu Prasību RFC", "Host_Requirements_RFC"). Tomēr visas trīs sistēmas autora apakštīklā un Solaris 2.2 joprojām to lieto. AIX 3.2.2 pielieto #term("eksponenciālu atkāpšanos", "exponential_backoff") noildzei, sūtot paketes pēc 0, 5, 15 un 35 sekundēm, kas ir ieteiktais veids. Mēs daudz vairāk runāsim par noildzēm 21.nodaļā.

Visbeidzot, ievērojiet, ka ICMP ziņojumus atgriež apmēram 3.5 ms pēc UDP datagrammas nosūtīšanas - kā redzēsim 7.nodaļā, tas ir līdzīgs #term("aprites", "round_trip") laikiem Ping pieprasījumos.

Tagi:
Izveidojis Kalvis Apsītis 2008-05-05 18:33
    
This wiki is licensed under a Creative Commons 2.0 license
XWiki Enterprise 6.4 - Documentation