Hálózat szimulációhoz írtam (valahol 2006 -ban) egy kis raw socket progit, ami napló alapján küldözget, apró csomagocskákat mintha azok különféle I címről jönnének. Most leporoltam ezt a progit, mivel a változatosság kedvéért broadcast csomagokat kellene küldenem a 255.255.255.255 -ös címre, ismét különféle ip címek szimulációjával. Hát nem megy. A 255.255.255.255 címre nem tudok küldeni "Permission denied" hibaüzenetet dob a program (természetesen root -ként futtatom). Ráadásul a gépben két hálókártya is van, viszont a socket nincs "bind" -elve egyikre sem.
Kérdések:
- miért nem működik a raw küldés a 255.255.255.255 címre?
- hogy kell egy raw socketet rábírni hogy egy adott interfészre dolgozzon?
Eddig nem találtam hasznosat a neten :(
- 2043 megtekintés
Hozzászólások
Ez a fuggveny egy Wake-On-LAN csomag kuldo programombol van, osszeallitja a WOL csomagot es kikuldi minden egyes interfeszen, ez alapjan elindulhatsz.
void SendWOLPacket(struct ether_addr * MACBin) {
int i;
sockfd=socket(PF_PACKET,SOCK_RAW,0);
if (sockfd==-1)
return;
iflist=if_namelist();
if (iflist==NULL) {
close(sockfd); sockfd=-1;
return;
}
for (i=0; iflist[i]!=NULL; i++) {
int Status;
int ifindex;
struct ifreq ifr;
byte PacketBuffer[256];
dword PacketLength;
byte * ptr;
int cnt;
struct sockaddr_ll dest;
strcpy(ifr.ifr_name,iflist[i]);
Status=ioctl(sockfd,SIOCGIFFLAGS,&ifr);
if (Status==-1)
continue;
if ((ifr.ifr_flags & IFF_UP)==0 || (ifr.ifr_flags & IFF_LOOPBACK)!=0 || (ifr.ifr_flags & IFF_MASTER)!=0)
continue;
strcpy(ifr.ifr_name,iflist[i]);
Status=ioctl(sockfd,SIOCGIFHWADDR,&ifr);
if (Status==-1 || (Status!=-1 && ifr.ifr_hwaddr.sa_family!=ARPHRD_ETHER))
continue;
ptr=PacketBuffer;
memcpy(ptr,&MACBin->ether_addr_octet,ETH_ALEN);
ptr+=ETH_ALEN;
memcpy(ptr,&ifr.ifr_hwaddr.sa_data,ETH_ALEN);
ptr+=ETH_ALEN;
*(word *)ptr=htons(WOL_ETHER_TYPE);
ptr+=sizeof(word);
strcpy(ifr.ifr_name,iflist[i]);
Status=ioctl(sockfd,SIOCGIFINDEX,&ifr);
if (Status==-1)
continue;
ifindex=ifr.ifr_ifindex;
memset(ptr,0xFF,ETH_ALEN);
ptr+=ETH_ALEN;
for (cnt=1; cnt<=16; cnt++) {
memcpy(ptr,&MACBin->ether_addr_octet,ETH_ALEN);
ptr+=ETH_ALEN;
}
PacketLength=(dword)ptr-(dword)PacketBuffer;
dest.sll_family=AF_PACKET;
dest.sll_ifindex=ifindex;
dest.sll_halen=ETH_ALEN;
memcpy(&dest.sll_addr,MACBin->ether_addr_octet,sizeof(MACBin->ether_addr_octet));
sendto(sockfd,PacketBuffer,PacketLength,0,(struct sockaddr *)&dest,sizeof(dest));
}
if_freenamelist(iflist); iflist=NULL;
close(sockfd); sockfd=-1;
}
(az
if_namelist()
sajat fuggveny, a
/proc/net/dev
-bol olvassa ki az interfeszek listajat, a byte/word/dword tipusok az uint8/16/32-t jelentik)
- A hozzászóláshoz be kell jelentkezni
- miért nem működik a raw küldés a 255.255.255.255 címre?
Lehet, hogy azért amiért a ping 255.255.255.255 sem?
- A hozzászóláshoz be kell jelentkezni
Te magad allitod elo az IP csomagot? A kernel elvben nem foglalkozik vele, hogy mit irsz bele, hanem ugy ahogy van, kiteszi a drotra.
sendip
-vel el tudod kuldeni a 255.255.255.255-re?
- A hozzászóláshoz be kell jelentkezni
Csak tippek, jó pongyolán:
Mivel nem multicast-ról hanem broadcast-ról beszélsz, azért vélhetően 1 db IP subnet-re / interface-re / ethernet szegmensre vagy korlátozva. A csomagodra ránézve a kernel több illeszkedő routing bejegyzést is talál, és valószínűleg 1 db sendmsg() hatására nem hajlandó két interface-en is beszélni. (Ha belegondolsz, miért álljunk meg két interface-nél; a 255.255.255.255-re küldve akár még a loopback-en is értelmesnek tekinthetnénk a broadcast megjelenését.)
Szerintem próbáld meg az egyes subnet-ek saját broadcast címét használni, és minden interface-en külön küldd ki a csomagot, ugyanannak a bind-olatlan socket-nek a felhasználásával. Vagy az elején csinálj két socket-et, külön-külön bind-olva (nem tudom, ez értelmes javaslat-e raw socket-nél: elvileg még protokollt sem választottál, így hogyan választhatnál portot). Vagy bridge-eld össze a két kártyát egyetlen ethernet szegmensbe (ha ezt így mondják), és akkor 1 db közös broadcast cím fog hozzájuk tartozni (gondolom).
- A hozzászóláshoz be kell jelentkezni
hali, ezen a linken el tudsz indulni:
http://www.security-freak.net/packet-injection/packet-injection.html
vagy ha az általad írt forrást megmutatod, lehet, hogy megtaláljuk a hibát.
üdv,
sbalazs.
- A hozzászóláshoz be kell jelentkezni
Először is mindenkinek köszönöm a hozzászólást!
Mivel órákig nem jött semmi (anno) feladtam, és a "broadcast" csomagok helyett sima UDP csomagokat küldözgettem, különféle "fake" forráscímmel ellátva - a teszthez ez elégséges volt. Úgyhogy megkerültem a problémát :)
Meglepő, hogy a raw socket és az egyéb, nem szigorúan felhasználói kommunikációval kapcsolatban (pl. ICMP) milyen kevés az információ/specifikáció. Ráadásul, mivel mind winben mind Linuxban programozgatok - tudathasadásom is van, mivel a két rwendszer számos ponton alapvető dolgokat másképp kezel. Továbbra sem tudom, hogy a RAW socket melyik ethernet kártyára kapcsolódik - úgy tűnik, hogy az IP címhez illeszt valahogy (lehet hogy a másik szegmensre definiált interfész is megkapja, csak kiszűri?)
Egébként, most épp a windows ping -et "kerülgettem", számos alig olvasható forráskódot átnéztem, mindegyik az icmp.dll API -ra támaszkodik amit az M$ eléggé elkenve dokumentált, azt is csak a CE verzióra (MSDN, SDK és egyéb WEB források). Néha azon csodálkozom, hogy tud ez az egész működni amikor ilyen barkács!?
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
Még mindig ugyanaz a projekt, de most kicsit más a gond.
Van egy kis raw socket küldözgető progim - kopasz C, az egész alig több 10 KB forrásnál. x.x.0.0 -tól x.x.3.254 -ig szór álvéletlen címekkel csomagokat. A program "magját" a csomag összeállítás képezi, teljesen szinkronban nyomja a csomagokat ahogy bírja. "Normál" (én annal tekintem állapotában ck. 2700 csomagot dob másodpercenként, a megadott cím és socket irányába. A túloldalon van a fejlesztés alatt álló program, ami veszi ezeket a csomagokat, és lerakja érkezési sorrendben egy fájlba, és ez windows -on zajlik. Azt kellet észrevennem, hogy időnként - teljesen változóan, akár 10 millió csomag után - egyszer csak kimerevedik, a log -ban azt látni, hogy az alsó réteg, eldobálja a csomagokat és a log FIFO teljesen betelik. Órákon át próbáltam mgérteni miért. össze-vissza trancsíroztam a kódot, míg rájöttem, hogy a primitív Linux oldali teszt programom időnként megvadul!? A szokásos 2.700 csomag helyett több mint 10.000 csomagot kezd küldeni! A Linux oldalt nem igen piszkálom, semmire sem használom, mitől tud ez így megtáltosodni? Hogy tudnám, valami egyszerű de biztonságos módon megfogni a sebességet?
(Kicsit lepusztult az agyam a sok órányi fölösleges debuggolástól)
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
A halozati eszkozok (hw-k) egeszen turhetoen kezelik a burst-okben kiadott csomagokat. Ezen felul, idoziteni, pl masodpercenkent _egyenletesen_ kikuldeni mondjuk 1000 csomagot elegge nehez (me'g tobbet meg nehezebb). Osszekapcsolva a kettot: masodpercenkent pl. 50x kikuldeni 20-as adagokban a csomagokat mar sokkal jobban kivitelezheto (egyenletesebb, stabilabb). Ebbe me'g beleteszel egy kis abszolut ido merest, novekmenyes algoritmussal, nanosleep/usleep/select + gettimeofday alapokon, es remelhetoleg jo lesz.
A.
- A hozzászóláshoz be kell jelentkezni
"Egy kis önreklám sosem árt" mottóval ajánlom gyors belekukkantásra a
timer_design.txt
-t és a
timer.[ch]
-t az udp_copy2-ből, vagy a debug üzeneteket az atomfapad
udpconn2.c
-ből.
- A hozzászóláshoz be kell jelentkezni
Mi lehet a hiba?
struture timespec upto, remain;
int i_lim, i_count;
...
i_count = atoi(argv[1]);
time(&upto.tv_sec);
upto.tv_sec++;
upto.tv_nsec = 0;
i_lim = 0;
do
{
//fill next packet
//send next packet
i_count--;
i_lim++;
if ( time(NULL) >= upto.tv_sec )
{
time(&upto.tv_sec);
upto.tv_sec++;
upto.tv_nsec = 0;
i_lim = 0;
}
if ( i_lim > 3000 )
{
nanosleep(&upto,&remain);
time(&upto.tv_sec);
upto.tv_sec++;
upto.tv_nsec = 0;
i_lim = 0;
}
} while ( i_count > 0 );
Időnként, beáll és vár!?
UI: miért nem tartja a formátumot a code elem sem?
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
Jó .( Már tudom relatív, idő kell nem abszolút :( Már csak az a gond, hogy honnan is? Mi adja meg nekem a kezdettől eltelt időt nsec -ben avagy mi tölti ki nekem a timespec struktúrát?
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
No, hát megtaláltam, a "clock_gettime" rutint - már csak azt nem értem, hogy akkor ez most nem a glibc része, mert a dokumentációban egy szóval nem említik. A /usr/include/time.h -ban azonban benne van, illetve a linkelésnél kell az "rt" könyvtár (-lrt).
Azonban a kódom még mindíg nem működik jól :( Valamit nagyon benézek :(
Egy biztos a feladat nem is olyan triviális, azaz be kell korlátoznom, mondjuk max 3000 csomag/sec -re.
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
Valami már alakul, de nem az igazi :(
(Bocs de még mindig nem tudom hogy kell megadni az hogy ne törölje a sor eleji space -ket :()
struct timespec wait,remaind;
long long int elapsed, tick_start;
...
i_lim = 0;
start_tick = tick_nsec();
do
{
if ( ++ i_lim > 300 )
{
elapsed = tick_nsec() - tick_start;
if ( elapsed < 100000000L && elapsed > 1000000L )
{
wait.tv_sec = 0;
wait.tv_nsec = 100000000L - elapsed;
nanosleep(&wait,&remain);
}
start_tick = tick_nsec();
i_lim = 0;
}
// itt összeállítom és elküldöm a csomagot
} while ...
long long int tick_nsec()
{
struct timespec tspec;
clock_gettime(CLOCK_REALTIME,&tspec);
return ( (long long int)(tspec.tv_sec * 1000000000L + tspec.tv_nsec) )
}
Sajnos ez sem tökéletes, a windows oldal 100 ms -ként nézi meg a puffert, és általában kb. 300 csomagot kezel le, de van hogy több mint 600 -at, és a következő ciklusban nem jön semmi!?
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni