====== Programovani soketu v C ====== ===== Sokety ===== * zakladni navod prace se sokety: * http://www.linuxhowtos.org/C_C++/socket.htm * navod na libovolny raw paket: * http://mixter.void.ru/rawip.html * http://www.tenouk.com/Module43a.html * super navod na broadcast: * http://beej.us/guide/bgnet/output/html/multipage/advanced.html#broadcast * blokovane cteni - timeout: * http://www.programmersheaven.com/mb/CandCPP/353252/353252/how-to-set-timeout-for-recvfrom-method/ * co jsou blokovane a neblokovane sockety .. neblokovany muze byt i bez select * http://www.cs.vsb.cz/grygarek/PS/sockets.html * co je vlastne select()? * http://www.root.cz/clanky/sokety-a-c-funkce-select/ ==== Datové typy a struktury pro HW nebo protokoly ==== * int může být někde 32 bit, někde třeba 16 bit, pokud potřebujeme určitou přesnou velikost, jsou užitečné typy * int8_t, uint8_t, int16_t, uint16_t ... int64_t, uint64_t * viz http://linux.die.net/man/3/int8_t * pokud používáme datové struktury * vkládají se někdy mezi jednotlivé atributy prazdné místa do paměti, * popřípadě se provádí nějaké optimalizace, které mohou zabrat více paměti, než ve skutečnosti chceme. * někdy potřebujeme, aby struktura zabírala stejné místo v paměti na všech architekturách * použijeme struct my_struct { uint8_t field1; uint16_t field2; } __attribute__((packed)); * výhody a nvýhody viz http://digitalvampire.org/blog/index.php/2006/07/31/why-you-shouldnt-use-__attribute__packed/ * některé architektury používají jiný formát ukládání čísel (big-endian, little-endian) * pro zachování stejného způsobu ukládání se používá funkce htons (HostTONetworkSmall), htonl .. #include uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); ==== Prace s adresami ==== * struct sockaddr je nejvice obecna * jednotlive struktury jsou mezi sebou prevoditelne, ale nemusi mit vubec stejnou delku!! Je treba si uvedomit, kam mohu kdy sahnout ve strukture. include // All pointers to socket address structures are often cast to pointers // to this type before use in various functions and system calls: struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address }; // IPv4 AF_INET sockets: struct sockaddr_in { short sin_family; // e.g. AF_INET, AF_INET6 unsigned short sin_port; // e.g. htons(3490) struct in_addr sin_addr; // see struct in_addr, below char sin_zero[8]; // zero this if you want to }; struct in_addr { unsigned long s_addr; // load with inet_pton() }; // IPv6 AF_INET6 sockets: struct sockaddr_in6 { u_int16_t sin6_family; // address family, AF_INET6 u_int16_t sin6_port; // port number, Network Byte Order u_int32_t sin6_flowinfo; // IPv6 flow information struct in6_addr sin6_addr; // IPv6 address u_int32_t sin6_scope_id; // Scope ID }; struct in6_addr { unsigned char s6_addr[16]; // load with inet_pton() }; // General socket address holding structure, big enough to hold either // struct sockaddr_in or struct sockaddr_in6 data: struct sockaddr_storage { sa_family_t ss_family; // address family // all this is padding, implementation specific, ignore it: char __ss_pad1[_SS_PAD1SIZE]; int64_t __ss_align; char __ss_pad2[_SS_PAD2SIZE]; }; ===== Broadcast ===== * pokrývá dvě vrstvy modelu ISO/OSI (spojová a síťová) * MAC broadcast (FF:FF:FF:FF:FF:FF) * rozlišujeme 2 druhy IP broadcastu * broadcastová adresa siťě (10.10.11.255) * globální broadcastová adresa (255.255.255.255) * zasílání broadcastu vyžaduje speciální oprávnění (flag) * globální nelze odeslat bez brány! * nelze odeslat lokální na jinou síť.. neví se, že je to bcast :) * příjem je podivný: * bcast neprojde pres router, jestliže nemá nastavený flag na přesměrovávání * oba typy IP bcastu dojdou na všechny zařízení, protože se to posílá MAC bcastem!! * ale!! aplikace která naslouchá na portu, například nc -u -l 9999, tak * přijímá globální bcast i síťový, ale jen pokud přijde z dostupné IP? (ze stejné sítě, existující IP adresy?) * TODO * zkusit hack.. odesílat vzdy na MAC FF:FF... a ruzne kombinace src, dst * z jine site poslat lokalni bcast pomoci specifikace ff:ff .. to by nemelo projit, kvuli nedostupnosti zdroje * kdyztak zkusit uplny fake... treba gw ip, gw mac, dst mac ff, dst ip global bcast * poslat jinou, ale funkční IP, FAKE SRC MAC brány a nebo kouknout, zde si to druha strana overuje existenci hosta arpeckem ==== Test příjmu broadcastu aplikací listen ==== * OTESTOVAT ZNOVU.. NC MA TEHDENCY UZAMCIT SE JEN NA JEDNU RCVIP.. MUSIM HO PO KAZDEM POKUSU ZABIT * A TEN MZ VERZE 0.40 NEUMI ZMENIT MAC, MALFORMUJE PKT * server je 10.10.11.20/25, ntb, wifi nc -l -p -u 9999 * z klienta pharaon (10.10.11.2, 192.168.100.1) v LAN došlo: mz eth0 -A 10.10.11.2 -B 255.255.255.255 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" mz eth0 -A 10.10.11.2 -B 10.10.11.127 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" * nedošlo (protože se posílalo na MAC brány?): mz eth0 -A 10.10.11.2 -B 10.10.11.128 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" mz eth0 -A 10.10.11.2 -B 10.10.11.255 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" * došlo na stroj, ale nedošlo do soketu (použila se BCAST MAC) mz eth0 -A 192.168.10.10 -B 10.10.11.127 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // z jiné sítě a neexistující mz eth0 -A 10.10.11.8 -B 255.255.255.255 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // neexistujici ip mz eth0 -A 10.10.11.3 -B 10.10.11.127 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // neexistujici ip mz eth0 -A 10.10.11.1 -B 10.10.11.127 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // ip brany, ale moje mac mz eth0 -A 192.168.100.1 -B 10.10.11.127 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // existující, ale jíná síť mz eth0 -A 192.168.100.1 -B 255.255.255.255 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // existující, ale jíná síť * zkusil jsem si nastavit jinou sit (192.168.20.20)... vůbec neodešlo z IF * ta 127 .. neví se, že je to bcast .. bere se to jako host a brána není * globální chce asi gw = že by taky nevěděl, že je to bcast? nebo prostě obecně to chce bránu? mz eth0 -A 192.168.20.20 -B 255.255.255.255 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // nebyla nastavená gw mz eth0 -A 192.168.20.20 -B 10.10.11.127 -t udp "dp=9999,p=36:30:34:36:36:30:30:31:39" // nevedel, ze je to bcast * staré informace.. zmatené :) * globální broadcast * nelze provést (v unixu), pokud není specifikovaná brána - neví se který adaptér použít? * přijímají jej všechny uzly v LAN (v promiscuitinim i normálním režimu) * přijímají jej UDP sockety, které jsou '''bindované na INADDR_ANY''' a zdrojová IP bcastu odpovídá síti některé z lokálních IP? * nc -l -u -p 9999 skončí s hláškou network unreacheable * broadcast z neplatné adresy * nelze provést, pokud není specifikovaná brána - neví se který adaptér použít? * přijímají jej všechny uzly v LAN (v promiscuitinim i normálním režimu) * přijímají jej uzly, které jsou '''bindovány na IP z dané sítě''' * nc -l -u -p 9999 skončí s hláškou network unrecheable * bind() na INADDR_ANY * příjmá broadcasty na všech Intf pokud jejich zdrojová adresa odpovídá nějaké z lokální podsítě * příjmá data adresované libovolné lokální IP adrese * při odesílání globálního broadcastu nebo bcastu pro nelokální subnet se použíje IP adresa zařízení s default gw * při odesílání unicast dat nebo bcastu pro lokální subnet se použíje odpovídající IP a Intf * odesílací intf lze specifikovat pomocí socketopt SO_BINDTODEVICE, ale vyžaduje práva roota a je obsolute * bind() na inet_addr("aaa.bbb.ccc.ddd") * nepřijímá žádné broadcasty * přijímá data pouze na intf odpovídající uvedené IP adrese * pro odesílání dat nebo broadcastu se použije uvedená IP