====== 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