| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701 |
- // SoftEther VPN Source Code - Developer Edition Master Branch
- // Cedar Communication Module
- // BridgeUnix.c
- // Ethernet Bridge Program (for UNIX)
- #ifdef OS_UNIX
- #include "BridgeUnix.h"
- #include "Server.h"
- #include "VLanUnix.h"
- #include "Mayaqua/Cfg.h"
- #include "Mayaqua/FileIO.h"
- #include "Mayaqua/Memory.h"
- #include "Mayaqua/Object.h"
- #include "Mayaqua/Str.h"
- #include "Mayaqua/TcpIp.h"
- #include "Mayaqua/Unix.h"
- #include <string.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <net/ethernet.h>
- #include <net/if.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #ifdef UNIX_SOLARIS
- #include <sys/sockio.h>
- #endif
- #ifdef BRIDGE_PCAP
- #include <pcap.h>
- #endif
- #ifdef BRIDGE_BPF
- #include <ifaddrs.h>
- #include <net/bpf.h>
- #include <net/if_types.h>
- #include <net/if_dl.h>
- #endif
- #ifdef UNIX_LINUX
- #include <linux/if_packet.h>
- struct my_tpacket_auxdata
- {
- UINT tp_status;
- UINT tp_len;
- UINT tp_snaplen;
- USHORT tp_mac;
- USHORT tp_net;
- USHORT tp_vlan_tci;
- USHORT tp_vlan_tpid;
- };
- #define MY_TP_STATUS_VLAN_VALID (1 << 4)
- #define MY_TP_STATUS_VLAN_TPID_VALID (1 << 6)
- #define MY_PACKET_AUXDATA 8
- #endif // UNIX_LINUX
- static LIST *eth_offload_list = NULL;
- // Initialize
- void InitEth()
- {
- eth_offload_list = NewList(NULL);
- }
- // Free
- void FreeEth()
- {
- if (eth_offload_list != NULL)
- {
- FreeStrList(eth_offload_list);
- eth_offload_list = NULL;
- }
- }
- // Check whether interface description string of Ethernet device can be retrieved in this system
- bool EthIsInterfaceDescriptionSupportedUnix()
- {
- bool ret = false;
- DIRLIST *d = EnumDir("/etc/sysconfig/networking/devices/");
- if (d == NULL)
- {
- return false;
- }
- if (d->NumFiles >= 1)
- {
- ret = true;
- }
- FreeDir(d);
- return ret;
- }
- // Get interface description string
- bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size)
- {
- char tmp[MAX_SIZE];
- bool ret = false;
- BUF *b;
- // Validate arguments
- if (name == NULL || str == NULL)
- {
- return false;
- }
- StrCpy(str, size, name);
- Format(tmp, sizeof(tmp), "/etc/sysconfig/networking/devices/ifcfg-%s", name);
- b = ReadDump(tmp);
- if (b != NULL)
- {
- char *line = CfgReadNextLine(b);
- if (IsEmptyStr(line) == false)
- {
- if (StartWith(line, "#"))
- {
- char tmp[MAX_SIZE];
- StrCpy(tmp, sizeof(tmp), line + 1);
- Trim(tmp);
- tmp[60] = 0;
- StrCpy(str, size, tmp);
- ret = true;
- }
- }
- Free(line);
- FreeBuf(b);
- }
- return ret;
- }
- // Open raw socket
- int UnixEthOpenRawSocket()
- {
- #ifdef UNIX_LINUX
- int s;
- s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (s < 0)
- {
- return INVALID_SOCKET;
- }
- else
- {
- return s;
- }
- #else // UNIX_LINUX
- return -1;
- #endif // UNIX_LINUX
- }
- // Is Ethernet device control supported?
- bool IsEthSupported()
- {
- #if defined(UNIX_LINUX)
- return IsEthSupportedLinux();
- #elif defined(UNIX_BSD)
- return true;
- #elif defined(UNIX_SOLARIS)
- return IsEthSupportedSolaris();
- #else
- return false;
- #endif
- }
- #ifdef UNIX_LINUX
- bool IsEthSupportedLinux()
- {
- int s;
- // Try to open a raw socket
- s = UnixEthOpenRawSocket();
- if (s == INVALID_SOCKET)
- {
- // fail
- return false;
- }
- // success
- closesocket(s);
- return true;
- }
- #endif // UNIX_LINUX
- #ifdef UNIX_SOLARIS
- bool IsEthSupportedSolaris()
- {
- return true;
- }
- #endif // UNIX_SOLARIS
- #ifdef UNIX_SOLARIS
- // Get Ethernet device list on Solaris
- TOKEN_LIST *GetEthListSolaris()
- {
- TOKEN_LIST *t;
- int i, s;
- LIST *o;
- o = NewListFast(CompareStr);
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s != INVALID_SOCKET)
- {
- struct lifnum lifn;
- lifn.lifn_family = AF_INET;
- lifn.lifn_flags = 0;
- if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) >= 0)
- {
- struct lifconf lifc;
- struct lifreq *buf;
- UINT numifs;
- UINT bufsize;
- numifs = lifn.lifn_count;
- Debug("NumIFs:%d\n",numifs);
- bufsize = numifs * sizeof(struct lifreq);
- buf = Malloc(bufsize);
- lifc.lifc_family = AF_INET;
- lifc.lifc_flags = 0;
- lifc.lifc_len = bufsize;
- lifc.lifc_buf = (char *) buf;
- if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) >= 0)
- {
- for (i = 0; i<numifs; i++)
- {
- if(StartWith(buf[i].lifr_name, "lo") == false) {
- Add(o, CopyStr(buf[i].lifr_name));
- }
- }
- }
- Free(buf);
- }
- closesocket(s);
- }
- Sort(o);
- t = ZeroMalloc(sizeof(TOKEN_LIST));
- t->NumTokens = LIST_NUM(o);
- t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
- for (i = 0; i < LIST_NUM(o); i++)
- {
- char *name = LIST_DATA(o, i);
- t->Token[i] = name;
- }
- ReleaseList(o);
- return t;
- }
- #endif // UNIX_SOLARIS
- #ifdef UNIX_LINUX
- // Get Ethernet device list on Linux
- TOKEN_LIST *GetEthListLinux(bool enum_normal, bool enum_rawip)
- {
- struct ifreq ifr;
- TOKEN_LIST *t;
- UINT i, n;
- int s;
- LIST *o;
- char name[MAX_SIZE];
- if (enum_normal == false && enum_rawip)
- {
- return ParseToken(BRIDGE_SPECIAL_IPRAW_NAME, NULL);
- }
- o = NewListFast(CompareStr);
- s = UnixEthOpenRawSocket();
- if (s != INVALID_SOCKET)
- {
- n = 0;
- for (i = 0;; i++)
- {
- Zero(&ifr, sizeof(ifr));
- ifr.ifr_ifindex = i;
- if (ioctl(s, SIOCGIFNAME, &ifr) >= 0)
- {
- n = 0;
- StrCpy(name, sizeof(name), ifr.ifr_name);
- Zero(&ifr, sizeof(ifr));
- StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
- if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0)
- {
- UINT type = ifr.ifr_hwaddr.sa_family;
- if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801)
- {
- if (IsInListStr(o, name) == false)
- {
- if (StartWith(name, "tap_") == false)
- {
- Add(o, CopyStr(name));
- }
- }
- }
- }
- }
- else
- {
- n++;
- if (n >= 64)
- {
- break;
- }
- }
- }
- closesocket(s);
- }
- Sort(o);
- t = ZeroMalloc(sizeof(TOKEN_LIST));
- t->NumTokens = LIST_NUM(o) + (enum_rawip ? 1 : 0);
- t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
- for (i = 0; i < LIST_NUM(o); i++)
- {
- char *name = LIST_DATA(o, i);
- t->Token[i] = name;
- }
- if (enum_rawip)
- {
- t->Token[t->NumTokens - 1] = CopyStr(BRIDGE_SPECIAL_IPRAW_NAME);
- }
- ReleaseList(o);
- return t;
- }
- #endif // UNIX_LINUX
- #ifdef BRIDGE_PCAP
- // Ethernet device list by Pcap API
- TOKEN_LIST *GetEthListPcap()
- {
- pcap_if_t *alldevs;
- char errbuf[PCAP_ERRBUF_SIZE];
- LIST *o;
- TOKEN_LIST *t;
- int i;
- o = NewListFast(CompareStr);
- if( pcap_findalldevs(&alldevs,errbuf) != -1)
- {
- pcap_if_t *dev = alldevs;
- while(dev != NULL)
- {
- pcap_t *p;
- // Device type will be unknown until open the device?
- p = pcap_open_live(dev->name, 0, false, 0, errbuf);
- if(p != NULL)
- {
- int datalink = pcap_datalink(p);
- // Debug("type:%s\n",pcap_datalink_val_to_name(datalink));
- pcap_close(p);
- if(datalink == DLT_EN10MB) {
- // Enumerate only Ethernet type device
- Add(o, CopyStr(dev->name));
- }
- }
- dev = dev->next;
- }
- pcap_freealldevs(alldevs);
- }
- Sort(o);
- t = ZeroMalloc(sizeof(TOKEN_LIST));
- t->NumTokens = LIST_NUM(o);
- t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
- for (i = 0; i < LIST_NUM(o); i++)
- {
- t->Token[i] = LIST_DATA(o, i);
- }
- ReleaseList(o);
- return t;
- }
- #endif // BRIDGE_PCAP
- #ifdef BRIDGE_BPF
- // Ethernet device list by BPF API
- TOKEN_LIST *GetEthListBpf()
- {
- struct ifaddrs *ifadrs;
- struct sockaddr_dl *sockadr;
- LIST *o;
- TOKEN_LIST *t;
- int i;
- o = NewListFast(CompareStr);
- // Enumerate network devices
- if(getifaddrs( &ifadrs ) == 0)
- {
- struct ifaddrs *ifadr = ifadrs;
- while(ifadr)
- {
- sockadr = (struct sockaddr_dl *)ifadr->ifa_addr;
- if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER)
- {
- // Is this Ethernet device?
- if(!IsInListStr(o,ifadr->ifa_name))
- {
- // Ignore the foregoing device (for device which have multiple MAC address)
- Add(o, CopyStr(ifadr->ifa_name));
- }
- }
- ifadr = ifadr -> ifa_next;
- }
- freeifaddrs(ifadrs);
- }
- Sort(o);
- t = ZeroMalloc(sizeof(TOKEN_LIST));
- t->NumTokens = LIST_NUM(o);
- t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
- for (i = 0; i < LIST_NUM(o); i++)
- {
- t->Token[i] = LIST_DATA(o, i);
- }
- ReleaseList(o);
- return t;
- }
- #endif // BRIDGE_BPF
- // Enumerate Ethernet devices
- TOKEN_LIST *GetEthList()
- {
- return GetEthListEx(NULL, true, false);
- }
- TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden, bool enum_normal, bool enum_rawip)
- {
- #if defined(UNIX_LINUX)
- return GetEthListLinux(enum_normal, enum_rawip);
- #elif defined(UNIX_SOLARIS)
- return GetEthListSolaris();
- #elif defined(BRIDGE_PCAP)
- return GetEthListPcap();
- #elif defined(BRIDGE_BPF)
- return GetEthListBpf();
- #else
- return NULL;
- #endif
- }
- #ifdef UNIX_LINUX
- // Open Ethernet device (Linux)
- ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
- {
- ETH *e;
- struct ifreq ifr;
- struct sockaddr_ll addr;
- int s;
- int index;
- bool aux_ok = false;
- CANCEL *c;
- // Validate arguments
- if (name == NULL)
- {
- return NULL;
- }
- if (StrCmpi(name, BRIDGE_SPECIAL_IPRAW_NAME) == 0)
- {
- return OpenEthLinuxIpRaw();
- }
- if (tapmode)
- {
- #ifndef NO_VLAN
- // In tap mode
- VLAN *v = NewTap(name, tapaddr, true);
- if (v == NULL)
- {
- return NULL;
- }
- e = ZeroMalloc(sizeof(ETH));
- e->Name = CopyStr(name);
- e->Title = CopyStr(name);
- e->Cancel = VLanGetCancel(v);
- e->IfIndex = 0;
- e->Socket = INVALID_SOCKET;
- e->Tap = v;
- return e;
- #else // NO_VLAN
- return NULL;
- #endif // NO_VLAN
- }
- s = UnixEthOpenRawSocket();
- if (s == INVALID_SOCKET)
- {
- return NULL;
- }
- Zero(&ifr, sizeof(ifr));
- StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
- if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
- {
- closesocket(s);
- return NULL;
- }
- index = ifr.ifr_ifindex;
- Zero(&addr, sizeof(addr));
- addr.sll_family = PF_PACKET;
- addr.sll_protocol = htons(ETH_P_ALL);
- addr.sll_ifindex = index;
- if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
- {
- closesocket(s);
- return NULL;
- }
- if (local == false)
- {
- // Enable promiscuous mode
- Zero(&ifr, sizeof(ifr));
- StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
- if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
- {
- // Failed
- closesocket(s);
- return NULL;
- }
- ifr.ifr_flags |= IFF_PROMISC;
- if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
- {
- // Failed
- closesocket(s);
- return NULL;
- }
- }
- if (true)
- {
- int val = 1;
- int ss_ret = setsockopt(s, SOL_PACKET, MY_PACKET_AUXDATA, &val, sizeof(val));
- if (ss_ret < 0)
- {
- Debug("eth(%s): setsockopt: PACKET_AUXDATA failed.\n", name);
- }
- else
- {
- Debug("eth(%s): setsockopt: PACKET_AUXDATA ok.\n", name);
- aux_ok = true;
- }
- }
- e = ZeroMalloc(sizeof(ETH));
- e->Name = CopyStr(name);
- e->Title = CopyStr(name);
- e->IfIndex = index;
- e->Socket = s;
- e->Linux_IsAuxDataSupported = aux_ok;
- c = NewCancel();
- UnixDeletePipe(c->pipe_read, c->pipe_write);
- c->pipe_read = c->pipe_write = -1;
- UnixSetSocketNonBlockingMode(s, true);
- c->SpecialFlag = true;
- c->pipe_read = s;
- e->Cancel = c;
- // Get MTU
- e->InitialMtu = EthGetMtu(e);
- if (tapmode == false)
- {
- if (GetGlobalServerFlag(GSF_LOCALBRIDGE_NO_DISABLE_OFFLOAD) == false)
- {
- bool b = false;
- LockList(eth_offload_list);
- {
- if (IsInListStr(eth_offload_list, name) == false)
- {
- b = true;
- Add(eth_offload_list, CopyStr(name));
- }
- }
- UnlockList(eth_offload_list);
- if (b)
- {
- // Disable hardware offloading
- UnixDisableInterfaceOffload(name);
- }
- }
- }
- return e;
- }
- #endif // UNIX_LINUX
- // Get the MTU value
- UINT EthGetMtu(ETH *e)
- {
- #if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- UINT ret = 0;
- #ifdef UNIX_SOLARIS
- struct lifreq ifr;
- #else // UNIX_SOLARIS
- struct ifreq ifr;
- #endif // UNIX_SOLARIS
- int s;
- // Validate arguments
- if (e == NULL || e->Tap != NULL)
- {
- return 0;
- }
- if (e->IsRawIpMode)
- {
- return 0;
- }
- if (e->CurrentMtu != 0)
- {
- return e->CurrentMtu;
- }
- #if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- s = e->SocketBsdIf;
- #else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- s = e->Socket;
- #endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- Zero(&ifr, sizeof(ifr));
- #ifdef UNIX_SOLARIS
- StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
- #else // UNIX_SOLARIS
- StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
- #endif // UNIX_SOLARIS
- #ifdef UNIX_SOLARIS
- if (ioctl(s, SIOCGLIFMTU, &ifr) < 0)
- {
- // failed
- return 0;
- }
- #else // UNIX_SOLARIS
- if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
- {
- // failed
- return 0;
- }
- #endif // UNIX_SOLARIS
- #ifdef UNIX_SOLARIS
- ret = ifr.lifr_mtu + 14;
- #else // UNIX_SOLARIS
- ret = ifr.ifr_mtu + 14;
- #endif // UNIX_SOLARIS
- e->CurrentMtu = ret;
- Debug("%s: GetMtu: %u\n", e->Name, ret);
- return ret;
- #else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- return 0;
- #endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- }
- // Set the MTU value
- bool EthSetMtu(ETH *e, UINT mtu)
- {
- #if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- UINT ret = 0;
- #ifdef UNIX_SOLARIS
- struct lifreq ifr;
- #else // UNIX_SOLARIS
- struct ifreq ifr;
- #endif // UNIX_SOLARIS
- int s;
- // Validate arguments
- if (e == NULL || e->Tap != NULL || (mtu > 1 && mtu < 1514))
- {
- return false;
- }
- if (mtu == 0 && e->InitialMtu == 0)
- {
- return false;
- }
- if (e->IsRawIpMode)
- {
- return false;
- }
- if (mtu == 0)
- {
- // Restore initial MTU value when parameter mtu == 0
- mtu = e->InitialMtu;
- }
- #if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- s = e->SocketBsdIf;
- #else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- s = e->Socket;
- #endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- if (e->CurrentMtu == mtu)
- {
- // No need to change
- return true;
- }
- Zero(&ifr, sizeof(ifr));
- #ifdef UNIX_SOLARIS
- StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
- ifr.lifr_mtu = mtu - 14;
- #else // UNIX_SOLARIS
- StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
- ifr.ifr_mtu = mtu - 14;
- #endif // UNIX_SOLARIS
- #ifdef UNIX_SOLARIS
- if (ioctl(s, SIOCSLIFMTU, &ifr) < 0)
- {
- // Failed
- return false;
- }
- #else // UNIX_SOLARIS
- if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
- {
- // Failed
- return false;
- }
- #endif // UNIX_SOLARIS
- e->CurrentMtu = mtu;
- Debug("%s: SetMtu: %u\n", e->Name, mtu);
- return true;
- #else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- return false;
- #endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- }
- // Is changing MTU supported?
- bool EthIsChangeMtuSupported(ETH *e)
- {
- #if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- // Validate arguments
- if (e == NULL || e->Tap != NULL)
- {
- return false;
- }
- if (e->IsRawIpMode)
- {
- return false;
- }
- return true;
- #else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- return false;
- #endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
- }
- #ifdef UNIX_SOLARIS
- // Open Ethernet adapter (Solaris)
- ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
- {
- char devname[MAX_SIZE];
- int fd;
- ETH *e;
- CANCEL *c;
- struct strioctl sioc;
- // Validate arguments
- if (name == NULL || tapmode != false)
- {
- return NULL;
- }
- // Parse device name
- if (ParseUnixEthDeviceName(devname, sizeof(devname), name) == false)
- {
- return NULL;
- }
- // Open the device - use style 1 attachment
- fd = open(devname, O_RDWR);
- if (fd == -1)
- {
- // Failed
- return NULL;
- }
- // Bind to SAP
- if (DlipBindRequest(fd) == false)
- {
- // Failed
- close(fd);
- return NULL;
- }
- // Verify ACK message
- if (DlipReceiveAck(fd) == false)
- {
- // Failed
- close(fd);
- return NULL;
- }
- // Set to ignore SAP and promiscuous mode
- if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
- {
- // Failed
- close(fd);
- return NULL;
- }
- // Verify ACK message
- if (DlipReceiveAck(fd) == false)
- {
- // Failed
- close(fd);
- return NULL;
- }
- // Set to the mode to receive self sending packet
- if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
- {
- // Failed
- close(fd);
- return NULL;
- }
- // Verify ACK message
- if (DlipReceiveAck(fd) == false)
- {
- // Failed
- close(fd);
- return NULL;
- }
- // Set to raw mode
- sioc.ic_cmd = DLIOCRAW;
- sioc.ic_timout = -1;
- sioc.ic_len = 0;
- sioc.ic_dp = NULL;
- if (ioctl(fd, I_STR, &sioc) < 0)
- {
- // Failed
- close(fd);
- return NULL;
- }
- if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
- {
- // Failed
- close(fd);
- return NULL;
- }
- e = ZeroMalloc(sizeof(ETH));
- e->Name = CopyStr(name);
- e->Title = CopyStr(name);
- c = NewCancel();
- UnixDeletePipe(c->pipe_read, c->pipe_write);
- c->pipe_read = c->pipe_write = -1;
- c->SpecialFlag = true;
- c->pipe_read = fd;
- e->Cancel = c;
- e->IfIndex = -1;
- e->Socket = fd;
- UnixSetSocketNonBlockingMode(fd, true);
- // Get control interface
- e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);
- // Get MTU value
- e->InitialMtu = EthGetMtu(e);
- return e;
- }
- // Set to promiscuous mode
- bool DlipPromiscuous(int fd, UINT level)
- {
- dl_promiscon_req_t req;
- struct strbuf ctl;
- int flags;
- // Validate arguments
- if (fd == -1)
- {
- return false;
- }
- Zero(&req, sizeof(req));
- req.dl_primitive = DL_PROMISCON_REQ;
- req.dl_level = level;
- Zero(&ctl, sizeof(ctl));
- ctl.maxlen = 0;
- ctl.len = sizeof(req);
- ctl.buf = (char *)&req;
- flags = 0;
- if (putmsg(fd, &ctl, NULL, flags) < 0)
- {
- return false;
- }
- return true;
- }
- // Bind to a SAP
- bool DlipBindRequest(int fd)
- {
- dl_bind_req_t req;
- struct strbuf ctl;
- if (fd == -1)
- {
- return false;
- }
- Zero(&req, sizeof(req));
- req.dl_primitive = DL_BIND_REQ;
- req.dl_service_mode = DL_CLDLS;
- req.dl_sap = 0;
- Zero(&ctl, sizeof(ctl));
- ctl.maxlen = 0;
- ctl.len = sizeof(req);
- ctl.buf = (char *)&req;
- if (putmsg(fd, &ctl, NULL, 0) < 0)
- {
- return false;
- }
- return true;
- }
- // Verify the ACK message
- bool DlipReceiveAck(int fd)
- {
- union DL_primitives *dlp;
- struct strbuf ctl;
- int flags = 0;
- char *buf;
- // Validate arguments
- if (fd == -1)
- {
- return false;
- }
- buf = MallocFast(SOLARIS_MAXDLBUF);
- Zero(&ctl, sizeof(ctl));
- ctl.maxlen = SOLARIS_MAXDLBUF;
- ctl.len = 0;
- ctl.buf = buf;
- if (getmsg(fd, &ctl, NULL, &flags) < 0)
- {
- return false;
- }
- dlp = (union DL_primitives *)ctl.buf;
- if (dlp->dl_primitive != (UINT)DL_OK_ACK && dlp->dl_primitive != (UINT)DL_BIND_ACK)
- {
- Free(buf);
- return false;
- }
- Free(buf);
- return true;
- }
- #endif // UNIX_SOLARIS
- // Validate device name and return proper device path according to system type
- bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, char *src_name)
- {
- UINT len, i;
- struct stat s;
- int err;
- char *device_path;
- int device_pathlen;
- // Validate arguments
- if (dst_devname == NULL || src_name == NULL)
- {
- return false;
- }
- // Check string length
- if (IsEmptyStr(src_name))
- {
- return false;
- }
- // Solaris 10 and higher make real and virtual devices available in /dev/net
- err = stat("/dev/net", &s);
- if (err != -1 && S_ISDIR(s.st_mode))
- {
- device_path = "/dev/net/";
- }
- else
- {
- device_path = "/dev/";
- }
- device_pathlen = StrLen(device_path);
- // Last character must be a number
- if (src_name[i] < '0' || '9' < src_name[i])
- {
- if (src_name[i + 1] == 0)
- {
- return false;
- }
- }
- StrCpy(dst_devname, dst_devname_size, device_path);
- StrCpy(dst_devname + device_pathlen, dst_devname_size - device_pathlen, src_name);
- dst_devname[device_pathlen + len] = 0;
- return true;
- }
- #if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP)
- // Initialize captured packet data structure
- struct CAPTUREBLOCK *NewCaptureBlock(UCHAR *data, UINT size) {
- struct CAPTUREBLOCK *block = Malloc(sizeof(struct CAPTUREBLOCK));
- block->Buf = data;
- block->Size = size;
- return block;
- }
- // Free captured packet data structure
- void FreeCaptureBlock(struct CAPTUREBLOCK *block) {
- Free(block);
- }
- #endif // BRIDGE_BPF || BRIDGE_PCAP
- #ifdef BRIDGE_PCAP
- // Callback function to receive arriving packet (Pcap)
- void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
- {
- ETH *e = (ETH *) user;
- struct CAPTUREBLOCK *block;
- UCHAR *data;
- data = Malloc(h->caplen);
- Copy(data, bytes, h->caplen);
- block = NewCaptureBlock(data, h->caplen);
- LockQueue(e->Queue);
- // Discard arriving packet when queue filled
- if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE) {
- InsertQueue(e->Queue, block);
- e->QueueSize += h->caplen;
- }
- UnlockQueue(e->Queue);
- Cancel(e->Cancel);
- return;
- }
- // Relay thread for captured packet (Pcap)
- void PcapThread(THREAD *thread, void *param)
- {
- ETH *e = (ETH *)param;
- pcap_t *p = e->Pcap;
- int ret;
- // Notify initialize completed
- NoticeThreadInit(thread);
- // Return -1:Error -2:Terminated externally
- ret = pcap_loop(p, -1, PcapHandler, (u_char *) e);
- if(ret == -1) {
- e->Socket = INVALID_SOCKET;
- pcap_perror(p, "capture");
- }
- return;
- }
- // Open Ethernet adapter (Pcap)
- ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr)
- {
- char errbuf[PCAP_ERRBUF_SIZE];
- ETH *e;
- pcap_t *p;
- // Validate arguments
- if (name == NULL || tapmode != false)
- {
- return NULL;
- }
- // Initialize error message buffer
- errbuf[0] = 0;
- // Open capturing device
- p = pcap_open_live(name, 65535, (local == false), 1, errbuf);
- if(p==NULL)
- {
- return NULL;
- }
- // Set to non-block mode
- // (In old BSD OSs, 'select(2)' don't block normally for BPF device. To prevent busy loop)
- /*
- if(pcap_setnonblock(p, true, errbuf) == -1)
- {
- Debug("pcap_setnonblock:%s\n",errbuf);
- pcap_close(p);
- return NULL;
- }
- */
- e = ZeroMalloc(sizeof(ETH));
- e->Name = CopyStr(name);
- e->Title = CopyStr(name);
- e->Queue = NewQueue();
- e->QueueSize = 0;
- e->Cancel = NewCancel();
- e->IfIndex = -1;
- e->Socket = pcap_get_selectable_fd(p);
- e->Pcap = p;
- e->CaptureThread = NewThread(PcapThread, e);
- WaitThreadInit(e->CaptureThread);
- return e;
- }
- #endif // BRIDGE_PCAP
- #ifdef BRIDGE_BPF
- #ifdef BRIDGE_BPF_THREAD
- // Relay thread for captured packet (BPF)
- void BpfThread(THREAD *thread, void *param)
- {
- ETH *e = (ETH *)param;
- int fd = e->Socket;
- int len;
- int rest; // Rest size in buffer
- UCHAR *next; // Head of next packet in buffer
- struct CAPTUREBLOCK *block; // Data to enqueue
- UCHAR *data;
- struct bpf_hdr *hdr;
- // Allocate the buffer
- UCHAR *buf = Malloc(e->BufSize);
- // Notify initialize completed
- NoticeThreadInit(thread);
- while(1) {
- // Determining to exit loop
- if(e->Socket == INVALID_SOCKET) {
- break;
- }
- rest = read(fd, buf, e->BufSize);
- if(rest < 0 && errno != EAGAIN) {
- // Error
- close(fd);
- e->Socket = INVALID_SOCKET;
- Free(buf);
- Cancel(e->Cancel);
- return;
- }
- next = buf;
- LockQueue(e->Queue);
- while(rest>0) {
- // Cut out a packet
- hdr = (struct bpf_hdr *)next;
- // Discard arriving packet when queue filled
- if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE) {
- data = Malloc(hdr->bh_caplen);
- Copy(data, next+(hdr->bh_hdrlen), hdr->bh_caplen);
- block = NewCaptureBlock(data, hdr->bh_caplen);
- InsertQueue(e->Queue, block);
- e->QueueSize += hdr->bh_caplen;
- }
- // Find the head of next packet
- rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
- next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
- }
- UnlockQueue(e->Queue);
- Cancel(e->Cancel);
- }
- Free(buf);
- Cancel(e->Cancel);
- return;
- }
- #endif // BRIDGE_BPF_THREAD
- // Open Ethernet adapter (BPF)
- ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
- {
- ETH *e;
- CANCEL *c;
- char devname[MAX_SIZE];
- int n = 0;
- int fd;
- int ret;
- UINT bufsize;
- struct ifreq ifr;
- struct timeval to;
- // Find unused bpf device and open it
- do {
- Format(devname, sizeof(devname), "/dev/bpf%d", n++);
- fd = open (devname, O_RDWR);
- if(fd<0) {
- perror("open");
- }
- } while(fd < 0 && errno == EBUSY);
- // No free bpf device was found
- if(fd < 0) {
- Debug("BPF: No minor number are free.\n");
- return NULL;
- }
- // Enlarge buffer size
- n = 524288; // Somehow(In libpcap, this size is 32768)
- while(true) {
- // Specify buffer size
- ioctl(fd, BIOCSBLEN, &n);
- // Bind to the network device
- StrCpy(ifr.ifr_name, IFNAMSIZ, name);
- ret = ioctl(fd, BIOCSETIF, &ifr);
- if(ret < 0) {
- if(ret == ENOBUFS && n>1500) {
- // Inappropriate buffer size
- // Retry with half buffer size
- // If buffer size is under 1500 bytes, something goes wrong
- n /= 2;
- continue;
- }
- Debug("bpf: binding network failed.\n");
- close(fd);
- return NULL;
- } else {
- break;
- }
- }
- bufsize = n;
- // Set to promiscuous mode
- if(local == false) {
- if (ioctl(fd, BIOCPROMISC, NULL) < 0) {
- printf("bpf: promisc mode failed.\n");
- close(fd);
- return NULL;
- }
- }
- // Set to immediate mode (Return immediately when packet arrives)
- n = 1;
- if (ioctl(fd, BIOCIMMEDIATE, &n) < 0) {
- Debug("BPF: non-block mode failed.\n");
- close(fd);
- return NULL;
- }
- // Set receiving self sending packet
- n = 1;
- if (ioctl(fd, BIOCGSEESENT, &n) < 0) {
- Debug("BPF: see sent mode failed.\n");
- close(fd);
- return NULL;
- }
- // Header complete mode (Generate whole header of sending packet)
- n = 1;
- if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0) {
- Debug("BPF: Header complete mode failed.\n");
- close(fd);
- return NULL;
- }
- // Set timeout delay to 1 second
- to.tv_sec = 1;
- to.tv_usec = 0;
- if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0) {
- Debug("BPF: Read timeout setting failed.\n");
- close(fd);
- return NULL;
- }
- e = ZeroMalloc(sizeof(ETH));
- e->Name = CopyStr(name);
- e->Title = CopyStr(name);
- e->IfIndex = -1;
- e->Socket = fd;
- e->BufSize = bufsize;
- #ifdef BRIDGE_BPF_THREAD
- e->Queue = NewQueue();
- e->QueueSize = 0;
- e->Cancel = NewCancel();
- // Start capture thread
- e->CaptureThread = NewThread(BpfThread, e);
- WaitThreadInit(e->CaptureThread);
- #else // BRIDGE_BPF_THREAD
- c = NewCancel();
- UnixDeletePipe(c->pipe_read, c->pipe_write);
- c->pipe_read = c->pipe_write = -1;
- c->SpecialFlag = true;
- c->pipe_read = fd;
- e->Cancel = c;
- e->Buffer = Malloc(bufsize);
- e->Next = e->Buffer;
- e->Rest = 0;
- // Set to non-blocking mode
- UnixSetSocketNonBlockingMode(fd, true);
- #endif // BRIDGE_BPF_THREAD
- // Open interface control socket for FreeBSD
- e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);
- // Get MTU value
- e->InitialMtu = EthGetMtu(e);
- return e;
- }
- #endif // BRIDGE_BPF
- #ifdef UNIX_BSD
- ETH *OpenEthBSD(char *name, bool local, bool tapmode, char *tapaddr)
- {
- if (tapmode)
- {
- #ifndef NO_VLAN
- // In tap mode
- VLAN *v = NewTap(name, tapaddr, true);
- if (v == NULL)
- {
- return NULL;
- }
- ETH *e;
- e = ZeroMalloc(sizeof(ETH));
- e->Name = CopyStr(name);
- e->Title = CopyStr(name);
- e->Cancel = VLanGetCancel(v);
- e->IfIndex = 0;
- e->Socket = INVALID_SOCKET;
- e->Tap = v;
- return e;
- #else // NO_VLAN
- return NULL:
- #endif // NO_VLAN
- }
- #if defined(BRIDGE_BPF)
- return OpenEthBpf(name, local, tapmode, tapaddr);
- #elif defined(BRIDGE_PCAP)
- return OpenEthPcap(name, local, tapmode, tapaddr);
- #else
- return NULL;
- #endif
- }
- #endif // UNIX_BSD
- // Open Ethernet adapter
- ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
- {
- #if defined(UNIX_LINUX)
- return OpenEthLinux(name, local, tapmode, tapaddr);
- #elif defined(UNIX_BSD)
- return OpenEthBSD(name, local, tapmode, tapaddr);
- #elif defined(UNIX_SOLARIS)
- return OpenEthSolaris(name, local, tapmode, tapaddr);
- #elif defined(BRIDGE_PCAP)
- return OpenEthPcap(name, local, tapmode, tapaddr);
- #elif defined(BRIDGE_BPF)
- return OpenEthBpf(name, local, tapmode, tapaddr);
- #else
- return NULL;
- #endif
- }
- typedef struct UNIXTHREAD
- {
- pthread_t thread;
- bool finished;
- } UNIXTHREAD;
- // Close Ethernet adapter
- void CloseEth(ETH *e)
- {
- // Validate arguments
- if (e == NULL)
- {
- return;
- }
- if (e->IsRawIpMode)
- {
- CloseEthLinuxIpRaw(e);
- return;
- }
- if (e->Tap != NULL)
- {
- #ifndef NO_VLAN
- FreeTap(e->Tap);
- #endif // NO_VLAN
- }
- #ifdef BRIDGE_PCAP
- {
- struct CAPTUREBLOCK *block;
- pcap_breakloop(e->Pcap);
- WaitThread(e->CaptureThread, INFINITE);
- ReleaseThread(e->CaptureThread);
- pcap_close(e->Pcap);
- while (block = GetNext(e->Queue)) {
- Free(block->Buf);
- FreeCaptureBlock(block);
- }
- ReleaseQueue(e->Queue);
- }
- #endif // BRIDGE_PCAP
- #ifdef BRIDGE_BPF
- #ifdef BRIDGE_BPF_THREAD
- {
- struct CAPTUREBLOCK *block;
- int fd = e->Socket;
- e->Socket = INVALID_SOCKET;
- WaitThread(e->CaptureThread, INFINITE);
- ReleaseThread(e->CaptureThread);
- e->Socket = fd; // restore to close after
- while (block = GetNext(e->Queue)) {
- Free(block->Buf);
- FreeCaptureBlock(block);
- }
- ReleaseQueue(e->Queue);
- }
- #else // BRIDGE_BPF_THREAD
- Free(e->Buffer);
- #endif // BRIDGE_BPF_THREAD
- #endif // BRIDGE_BPF
- ReleaseCancel(e->Cancel);
- Free(e->Name);
- Free(e->Title);
- // Restore MTU value
- EthSetMtu(e, 0);
- if (e->Socket != INVALID_SOCKET)
- {
- #if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP) || defined(UNIX_SOLARIS)
- close(e->Socket);
- #else // BRIDGE_PCAP
- closesocket(e->Socket);
- #endif // BRIDGE_PCAP
- #if defined(BRIDGE_BPF) || defined(UNIX_SOLARIS)
- if (e->SocketBsdIf != INVALID_SOCKET)
- {
- close(e->SocketBsdIf);
- }
- #endif // BRIDGE_BPF || UNIX_SOLARIS
- }
- Free(e);
- }
- // Get cancel object
- CANCEL *EthGetCancel(ETH *e)
- {
- CANCEL *c;
- // Validate arguments
- if (e == NULL)
- {
- return NULL;
- }
- c = e->Cancel;
- AddRef(c->ref);
- return c;
- }
- // Read a packet
- UINT EthGetPacket(ETH *e, void **data)
- {
- // Validate arguments
- if (e == NULL || data == NULL)
- {
- return INFINITE;
- }
- #ifdef UNIX_LINUX
- if (e->IsRawIpMode)
- {
- return EthGetPacketLinuxIpRaw(e, data);
- }
- #endif
- if (e->Tap != NULL)
- {
- #ifndef NO_VLAN
- // TAP mode
- void *buf;
- UINT size;
- if (VLanGetNextPacket(e->Tap, &buf, &size) == false)
- {
- return INFINITE;
- }
- *data = buf;
- return size;
- #else
- return INFINITE;
- #endif
- }
- #if defined(UNIX_LINUX)
- return EthGetPacketLinux(e, data);
- #elif defined(UNIX_SOLARIS)
- return EthGetPacketSolaris(e, data);
- #elif defined(BRIDGE_PCAP)
- return EthGetPacketPcap(e, data);
- #elif defined(BRIDGE_BPF)
- return EthGetPacketBpf(e, data);
- #endif
- }
- #ifdef UNIX_LINUX
- UINT EthGetPacketLinux(ETH *e, void **data)
- {
- int s, ret;
- UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
- struct iovec msg_iov;
- struct msghdr msg_header;
- struct cmsghdr *cmsg;
- union
- {
- struct cmsghdr cmsg;
- char buf[CMSG_SPACE(sizeof(struct my_tpacket_auxdata))];
- } cmsg_buf;
- s = e->Socket;
- if (s == INVALID_SOCKET)
- {
- return INFINITE;
- }
- // Read
- msg_iov.iov_base = tmp;
- msg_iov.iov_len = sizeof(tmp);
- msg_header.msg_name = NULL;
- msg_header.msg_namelen = 0;
- msg_header.msg_iov = &msg_iov;
- msg_header.msg_iovlen = 1;
- if (e->Linux_IsAuxDataSupported)
- {
- memset(&cmsg_buf, 0, sizeof(cmsg_buf));
- msg_header.msg_control = &cmsg_buf;
- msg_header.msg_controllen = sizeof(cmsg_buf);
- }
- else
- {
- msg_header.msg_control = NULL;
- msg_header.msg_controllen = 0;
- }
- msg_header.msg_flags = 0;
- ret = recvmsg(s, &msg_header, 0);
- if (ret == 0 || (ret == -1 && errno == EAGAIN))
- {
- // No packet
- *data = NULL;
- return 0;
- }
- else if (ret == -1 || ret > sizeof(tmp))
- {
- // Error
- *data = NULL;
- e->Socket = INVALID_SOCKET;
- return INFINITE;
- }
- else
- {
- bool flag = false;
- USHORT api_vlan_id = 0;
- USHORT api_vlan_tpid = 0;
- if (e->Linux_IsAuxDataSupported)
- {
- for (cmsg = CMSG_FIRSTHDR(&msg_header); cmsg; cmsg = CMSG_NXTHDR(&msg_header, cmsg))
- {
- struct my_tpacket_auxdata *aux;
- UINT len;
- USHORT vlan_tpid = 0x8100;
- USHORT vlan_id = 0;
- if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct my_tpacket_auxdata)) ||
- cmsg->cmsg_level != SOL_PACKET ||
- cmsg->cmsg_type != MY_PACKET_AUXDATA)
- {
- continue;
- }
- aux = (struct my_tpacket_auxdata *)CMSG_DATA(cmsg);
- if (aux != NULL)
- {
- if (aux->tp_vlan_tci != 0)
- {
- vlan_id = aux->tp_vlan_tci;
- }
- }
- if (vlan_id != 0)
- {
- api_vlan_id = vlan_id;
- api_vlan_tpid = vlan_tpid;
- break;
- }
- }
- if (api_vlan_id != 0 && api_vlan_tpid != 0)
- {
- // VLAN ID has been received with PACKET_AUXDATA.
- // Insert the tag.
- USHORT vlan_id_ne = Endian16(api_vlan_id);
- USHORT vlan_tpid_ne = Endian16(api_vlan_tpid);
- if (ret >= 14)
- {
- if (*((USHORT *)(tmp + 12)) != vlan_tpid_ne)
- {
- *data = MallocFast(ret + 4);
- Copy(*data, tmp, 12);
- Copy(((UCHAR *)*data) + 12, &vlan_tpid_ne, 2);
- Copy(((UCHAR *)*data) + 14, &vlan_id_ne, 2);
- Copy(((UCHAR *)*data) + 16, tmp + 12, ret - 12);
- flag = true;
- ret += 4;
- }
- }
- }
- }
- // Success to read a packet (No VLAN)
- if (flag == false)
- {
- *data = MallocFast(ret);
- Copy(*data, tmp, ret);
- }
- return ret;
- }
- return 0;
- }
- #endif // UNIX_LINUX
- #ifdef UNIX_SOLARIS
- UINT EthGetPacketSolaris(ETH *e, void **data)
- {
- UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
- struct strbuf buf;
- int s;
- int flags = 0;
- int ret;
- s = e->Socket;
- if (s == INVALID_SOCKET)
- {
- return INFINITE;
- }
- Zero(&buf, sizeof(buf));
- buf.buf = tmp;
- buf.maxlen = sizeof(tmp);
- ret = getmsg(s, NULL, &buf, &flags);
- if (ret < 0 || ret > sizeof(tmp))
- {
- if (errno == EAGAIN)
- {
- // No packet
- *data = NULL;
- return 0;
- }
- // Error
- *data = NULL;
- return INFINITE;
- }
- ret = buf.len;
- *data = MallocFast(ret);
- Copy(*data, tmp, ret);
- return ret;
- }
- #endif // UNIX_SOLARIS
- #ifdef BRIDGE_PCAP
- UINT EthGetPacketPcap(ETH *e, void **data)
- {
- struct CAPTUREBLOCK *block;
- UINT size;
- LockQueue(e->Queue);
- block = GetNext(e->Queue);
- if(block != NULL) {
- e->QueueSize -= block->Size;
- }
- UnlockQueue(e->Queue);
- if(block == NULL) {
- *data = NULL;
- if(e->Socket == INVALID_SOCKET) {
- return INFINITE;
- }
- return 0;
- }
- *data = block->Buf;
- size = block->Size;
- FreeCaptureBlock(block);
- return size;
- }
- #endif // BRIDGE_PCAP
- #ifdef BRIDGE_BPF
- #ifdef BRIDGE_BPF_THREAD
- UINT EthGetPacketBpf(ETH *e, void **data)
- {
- struct CAPTUREBLOCK *block;
- UINT size;
- LockQueue(e->Queue);
- block = GetNext(e->Queue);
- if(block != NULL) {
- e->QueueSize -= block->Size;
- }
- UnlockQueue(e->Queue);
- if(block == NULL) {
- *data = NULL;
- if(e->Socket == INVALID_SOCKET) {
- return INFINITE;
- }
- return 0;
- }
- *data = block->Buf;
- size = block->Size;
- FreeCaptureBlock(block);
- return size;
- }
- #else // BRIDGE_BPF_THREAD
- UINT EthGetPacketBpf(ETH *e, void **data)
- {
- struct bpf_hdr *hdr;
- if(e->Rest<=0) {
- e->Rest = read(e->Socket, e->Buffer, e->BufSize);
- if(e->Rest < 0) {
- *data = NULL;
- if(errno != EAGAIN) {
- // Error
- return INFINITE;
- }
- // No packet
- return 0;
- }
- e->Next = e->Buffer;
- }
- // Cut out a packet
- hdr = (struct bpf_hdr *)e->Next;
- *data = Malloc(hdr->bh_caplen);
- Copy(*data, e->Next+(hdr->bh_hdrlen), hdr->bh_caplen);
- // Find the head of next packet
- e->Rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
- e->Next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
- return hdr->bh_caplen;
- }
- #endif // BRIDGE_BPF_THREAD
- #endif // BRIDGE_BPF
- // Send multiple packets
- void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
- {
- UINT i;
- // Validate arguments
- if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
- {
- return;
- }
- for (i = 0; i < num; i++)
- {
- EthPutPacket(e, datas[i], sizes[i]);
- }
- }
- // Send a packet
- void EthPutPacket(ETH *e, void *data, UINT size)
- {
- int s, ret;
- // Validate arguments
- if (e == NULL || data == NULL)
- {
- return;
- }
- if (e->IsRawIpMode)
- {
- EthPutPacketLinuxIpRaw(e, data, size);
- return;
- }
- if (size < 14 || size > MAX_PACKET_SIZE)
- {
- Free(data);
- return;
- }
- if (e->Tap != NULL)
- {
- #ifndef NO_VLAN
- // tap mode
- VLanPutPacket(e->Tap, data, size);
- #endif // NO_VLAN
- return;
- }
- s = e->Socket;
- if (s == INVALID_SOCKET)
- {
- Free(data);
- return;
- }
- // Send to device
- #ifdef BRIDGE_PCAP
- ret = pcap_inject(e->Pcap, data, size);
- if( ret == -1 ) {
- #ifdef _DEBUG
- pcap_perror(e->Pcap, "inject");
- #endif // _DEBUG
- Debug("EthPutPacket: ret:%d size:%d\n", ret, size);
- }
- #else // BRIDGE_PCAP
- #ifndef UNIX_LINUX
- ret = write(s, data, size);
- if (ret<0)
- {
- Debug("EthPutPacket: ret:%d errno:%d size:%d\n", ret, errno, size);
- }
- #else // UNIX_LINUX
- {
- struct iovec msg_iov;
- struct msghdr msg_header;
- msg_iov.iov_base = data;
- msg_iov.iov_len = size;
- msg_header.msg_name = NULL;
- msg_header.msg_namelen = 0;
- msg_header.msg_iov = &msg_iov;
- msg_header.msg_iovlen = 1;
- msg_header.msg_control = NULL;
- msg_header.msg_controllen = 0;
- msg_header.msg_flags = 0;
- ret = sendmsg(s, &msg_header, 0);
- if (ret<0)
- {
- Debug("EthPutPacket: ret:%d errno:%d size:%d\n", ret, errno, size);
- }
- }
- #endif // UNIX_LINUX
- #endif //BRIDGE_PCAP
- Free(data);
- }
- // Open ETH by using IP raw packets
- ETH *OpenEthLinuxIpRaw()
- {
- ETH *e;
- if (IsRawIpBridgeSupported() == false)
- {
- return NULL;
- }
- e = ZeroMalloc(sizeof(ETH));
- e->IsRawIpMode = true;
- e->RawTcp = NewUDP4(MAKE_SPECIAL_PORT(IPPROTO_TCP), NULL);
- e->RawUdp = NewUDP4(MAKE_SPECIAL_PORT(IPPROTO_UDP), NULL);
- e->RawIcmp = NewUDP4(MAKE_SPECIAL_PORT(IPPROTO_ICMP), NULL);
- if (e->RawTcp == NULL || e->RawUdp == NULL || e->RawIcmp == NULL)
- {
- ReleaseSock(e->RawTcp);
- ReleaseSock(e->RawUdp);
- ReleaseSock(e->RawIcmp);
- Free(e);
- return NULL;
- }
- ClearSockDfBit(e->RawTcp);
- ClearSockDfBit(e->RawUdp);
- ClearSockDfBit(e->RawIcmp);
- SetRawSockHeaderIncludeOption(e->RawTcp, true);
- SetRawSockHeaderIncludeOption(e->RawUdp, true);
- SetRawSockHeaderIncludeOption(e->RawIcmp, true);
- e->Name = CopyStr(BRIDGE_SPECIAL_IPRAW_NAME);
- e->Title = CopyStr(BRIDGE_SPECIAL_IPRAW_NAME);
- e->Cancel = NewCancel();
- UnixDeletePipe(e->Cancel->pipe_read, e->Cancel->pipe_write);
- e->Cancel->pipe_read = e->Cancel->pipe_write = -1;
- UnixSetSocketNonBlockingMode(e->RawTcp->socket, true);
- UnixSetSocketNonBlockingMode(e->RawUdp->socket, true);
- UnixSetSocketNonBlockingMode(e->RawIcmp->socket, true);
- e->Cancel->SpecialFlag = true;
- e->Cancel->pipe_read = e->RawTcp->socket;
- e->Cancel->pipe_special_read2 = e->RawUdp->socket;
- e->Cancel->pipe_special_read3 = e->RawIcmp->socket;
- e->RawIpMyMacAddr[2] = 0x01;
- e->RawIpMyMacAddr[5] = 0x01;
- SetIP(&e->MyIP, 10, 171, 7, 253);
- SetIP(&e->YourIP, 10, 171, 7, 254);
- e->RawIpSendQueue = NewQueueFast();
- e->RawIP_TmpBufferSize = 67000;
- e->RawIP_TmpBuffer = Malloc(e->RawIP_TmpBufferSize);
- return e;
- }
- // Close ETH by using IP raw packets
- void CloseEthLinuxIpRaw(ETH *e)
- {
- if (e == NULL)
- {
- return;
- }
- while (true)
- {
- BUF *buf = GetNext(e->RawIpSendQueue);
- if (buf == NULL)
- {
- break;
- }
- FreeBuf(buf);
- }
- ReleaseQueue(e->RawIpSendQueue);
- Free(e->Name);
- Free(e->Title);
- ReleaseSock(e->RawTcp);
- ReleaseSock(e->RawUdp);
- ReleaseSock(e->RawIcmp);
- ReleaseCancel(e->Cancel);
- Free(e->RawIP_TmpBuffer);
- Free(e);
- }
- // Receive an IP raw packet
- UINT EthGetPacketLinuxIpRaw(ETH *e, void **data)
- {
- UINT r;
- BUF *b;
- // Validate arguments
- if (e == NULL || data == NULL)
- {
- return INFINITE;
- }
- if (e->RawIp_HasError)
- {
- return INFINITE;
- }
- b = GetNext(e->RawIpSendQueue);
- if (b != NULL)
- {
- UINT size;
- *data = b->Buf;
- size = b->Size;
- Free(b);
- return size;
- }
- r = EthGetPacketLinuxIpRawForSock(e, data, e->RawTcp, IP_PROTO_TCP);
- if (r == 0)
- {
- r = EthGetPacketLinuxIpRawForSock(e, data, e->RawUdp, IP_PROTO_UDP);
- if (r == 0)
- {
- r = EthGetPacketLinuxIpRawForSock(e, data, e->RawIcmp, IP_PROTO_ICMPV4);
- }
- }
- if (r == INFINITE)
- {
- e->RawIp_HasError = true;
- }
- return r;
- }
- // Receive an IP raw packet for the specified socket
- UINT EthGetPacketLinuxIpRawForSock(ETH *e, void **data, SOCK *s, UINT proto)
- {
- UCHAR *tmp;
- UINT r;
- IP src_addr;
- UINT src_port;
- UINT ret = INFINITE;
- UCHAR *retbuf;
- PKT *p;
- bool ok = false;
- // Validate arguments
- if (e == NULL || data == NULL)
- {
- return INFINITE;
- }
- tmp = e->RawIP_TmpBuffer;
- LABEL_RETRY:
- *data = NULL;
- r = RecvFrom(s, &src_addr, &src_port, tmp, e->RawIP_TmpBufferSize);
- if (r == SOCK_LATER)
- {
- return 0;
- }
- if (r == 0)
- {
- if (s->IgnoreRecvErr)
- {
- return 0;
- }
- else
- {
- return INFINITE;
- }
- }
- ret = 14 + r;
- retbuf = Malloc(ret);
- *data = retbuf;
- Copy(retbuf, e->RawIpYourMacAddr, 6);
- Copy(retbuf + 6, e->RawIpMyMacAddr, 6);
- retbuf[12] = 0x08;
- retbuf[13] = 0x00;
- Copy(retbuf + 14, tmp, r);
- // Mangle packet
- p = ParsePacket(retbuf, ret);
- if (p != NULL)
- {
- if (p->TypeL3 == L3_IPV4)
- {
- IPV4_HEADER *ip;
- IP original_dest_ip;
- ip = p->L3.IPv4Header;
- UINTToIP(&original_dest_ip, ip->DstIP);
- if (IsZeroIP(&e->MyPhysicalIPForce) == false && CmpIpAddr(&e->MyPhysicalIPForce, &original_dest_ip) == 0 ||
- (IsIPMyHost(&original_dest_ip) && IsLocalHostIP(&original_dest_ip) == false && IsHostIPAddress4(&original_dest_ip)))
- {
- if (IsZeroIP(&e->MyPhysicalIPForce) && CmpIpAddr(&e->MyPhysicalIP, &original_dest_ip) != 0)
- {
- // Update MyPhysicalIP
- Copy(&e->MyPhysicalIP, &original_dest_ip, sizeof(IP));
- // Debug("e->MyPhysicalIP = %r\n", &e->MyPhysicalIP);
- }
- if (IsZeroIP(&e->MyPhysicalIPForce) == false)
- {
- Copy(&e->MyPhysicalIP, &e->MyPhysicalIPForce, sizeof(IP));
- }
- ip->DstIP = IPToUINT(&e->YourIP);
- ip->Checksum = 0;
- ip->Checksum = IpChecksum(ip, IPV4_GET_HEADER_LEN(ip) * 5);
- if (p->TypeL4 == L4_TCP)
- {
- TCP_HEADER *tcp = p->L4.TCPHeader;
- /*
- if (Endian16(tcp->SrcPort) == 80)
- {
- IP a, b;
- UINTToIP(&a, ip->SrcIP);
- UINTToIP(&b, ip->DstIP);
- Debug("%r %r %u %u\n", &a, &b, Endian16(tcp->SrcPort), Endian16(tcp->DstPort));
- }*/
- ok = true;
- }
- else if (p->TypeL4 == L4_UDP)
- {
- UDP_HEADER *udp = p->L4.UDPHeader;
- udp->Checksum = 0;
- ok = true;
- }
- else if (p->TypeL4 == L4_ICMPV4)
- {
- ICMP_HEADER *icmp = p->L4.ICMPHeader;
- if (icmp->Type == ICMP_TYPE_DESTINATION_UNREACHABLE || icmp->Type == ICMP_TYPE_TIME_EXCEEDED)
- {
- // Rewrite the Src IP of the IPv4 header of the ICMP response packet
- UINT size = p->PacketSize - ((UCHAR *)icmp - (UCHAR *)p->PacketData);
- UCHAR *data = (UCHAR *)icmp;
- IPV4_HEADER *orig_ipv4 = (IPV4_HEADER *)(((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- UINT orig_ipv4_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- UINT orig_ipv4_header_size = GetIpHeaderSize((UCHAR *)orig_ipv4, orig_ipv4_size);
- if (orig_ipv4_header_size >= sizeof(IPV4_HEADER) && orig_ipv4_size >= orig_ipv4_header_size)
- {
- if (orig_ipv4->Protocol == IP_PROTO_ICMPV4)
- {
- // Search the inner ICMP header
- UINT inner_icmp_size = orig_ipv4_size - orig_ipv4_header_size;
- if (inner_icmp_size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- ICMP_HEADER *inner_icmp = (ICMP_HEADER *)(((UCHAR *)data) +
- sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + orig_ipv4_header_size);
- if (inner_icmp->Type == ICMP_TYPE_ECHO_REQUEST)
- {
- ICMP_ECHO *inner_echo = (ICMP_ECHO *)(((UCHAR *)inner_icmp) + sizeof(ICMP_HEADER));
- inner_icmp->Checksum = 0;
- orig_ipv4->SrcIP = IPToUINT(&e->YourIP);
- orig_ipv4->Checksum = 0;
- orig_ipv4->Checksum = IpChecksum(orig_ipv4, orig_ipv4_header_size);
- // Rewrite the outer ICMP header
- if (true)
- {
- UCHAR *payload;
- UINT payload_size;
- ICMP_ECHO *echo;
- // Echo Response
- echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
- if (size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
- payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- // Rewrite the header
- icmp->Checksum = 0;
- icmp->Checksum = IpChecksum(icmp, size);
- }
- }
- }
- }
- }
- }
- }
- icmp->Checksum = 0;
- icmp->Checksum = IpChecksum(icmp, p->PayloadSize);
- ok = true;
- }
- else if (p->TypeL4 == L4_FRAGMENT)
- {
- ok = true;
- }
- }
- }
- FreePacket(p);
- }
- if (ok == false)
- {
- Free(*data);
- *data = NULL;
- goto LABEL_RETRY;
- }
- return ret;
- }
- // Send internal IP packet (insert into the send queue)
- void EthSendIpPacketInnerIpRaw(ETH *e, void *data, UINT size, USHORT protocol)
- {
- BUF *b;
- if (e == NULL || data == NULL || size == 0)
- {
- return;
- }
- if (e->RawIpSendQueue->num_item >= 1024)
- {
- return;
- }
- b = NewBuf();
- WriteBuf(b, e->RawIpYourMacAddr, 6);
- WriteBuf(b, e->RawIpMyMacAddr, 6);
- WriteBufShort(b, protocol);
- WriteBuf(b, data, size);
- SeekBufToBegin(b);
- InsertQueue(e->RawIpSendQueue, b);
- }
- // Process the packet internal if necessary
- bool EthProcessIpPacketInnerIpRaw(ETH *e, PKT *p)
- {
- bool ret = false;
- if (e == NULL || p == NULL)
- {
- return false;
- }
- if (p->TypeL3 == L3_ARPV4)
- {
- // ARP processing
- ARPV4_HEADER *arp = p->L3.ARPv4Header;
- if (Endian16(arp->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
- Endian16(arp->ProtocolType) == MAC_PROTO_IPV4 &&
- arp->HardwareSize == 6 && arp->ProtocolType == 4)
- {
- if (IPToUINT(&e->MyIP) == arp->TargetIP)
- {
- if (Endian16(arp->Operation) == ARP_OPERATION_REQUEST)
- {
- ARPV4_HEADER r;
- Zero(&r, sizeof(r));
- r.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
- r.ProtocolType = Endian16(MAC_PROTO_IPV4);
- r.HardwareSize = 6;
- r.ProtocolSize = 4;
- r.Operation = Endian16(ARP_OPERATION_RESPONSE);
- Copy(r.SrcAddress, e->RawIpMyMacAddr, 6);
- Copy(r.TargetAddress, arp->SrcAddress, 6);
- r.SrcIP = IPToUINT(&e->MyIP);
- r.TargetIP = arp->SrcIP;
- EthSendIpPacketInnerIpRaw(e, &r, sizeof(ARPV4_HEADER), MAC_PROTO_ARPV4);
- }
- }
- }
- }
- else if (p->TypeL3 == L3_IPV4 && p->TypeL4 == L4_UDP && p->TypeL7 == L7_DHCPV4)
- {
- // DHCP processing
- DHCPV4_HEADER *dhcp;
- UCHAR *data;
- UINT size;
- UINT dhcp_header_size;
- UINT dhcp_data_offset;
- UINT tran_id;
- UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
- bool ok;
- DHCP_OPTION_LIST *opt;
- dhcp = p->L7.DHCPv4Header;
- tran_id = Endian32(dhcp->TransactionId);
- // Get the DHCP data and size
- dhcp_header_size = sizeof(DHCPV4_HEADER);
- dhcp_data_offset = (UINT)(((UCHAR *)p->L7.DHCPv4Header) - ((UCHAR *)p->MacHeader) + dhcp_header_size);
- data = ((UCHAR *)dhcp) + dhcp_header_size;
- size = p->PacketSize - dhcp_data_offset;
- if (dhcp_header_size < 5)
- {
- // Data size is invalid
- return false;
- }
- // Search for Magic Cookie
- ok = false;
- while (size >= 5)
- {
- if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
- {
- // Found
- data += 4;
- size -= 4;
- ok = true;
- break;
- }
- data++;
- size--;
- }
- if (ok == false)
- {
- // The packet is invalid
- return false;
- }
- // Parse DHCP options list
- opt = ParseDhcpOptionList(data, size);
- if (opt == NULL)
- {
- // The packet is invalid
- return false;
- }
- if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST || opt->Opcode == DHCP_INFORM))
- {
- // Operate as the server
- UINT ip = IPToUINT(&e->YourIP);
- if (ip != 0 || opt->Opcode == DHCP_INFORM)
- {
- // Respond if there is providable IP address
- DHCP_OPTION_LIST ret;
- LIST *o;
- UINT hw_type = 0U;
- UINT hw_addr_size = 0U;
- UINT new_ip = ip;
- IP default_dns;
- Zero(&default_dns, sizeof(default_dns));
- Zero(&ret, sizeof(ret));
- ret.Opcode = (opt->Opcode == DHCP_DISCOVER ? DHCP_OFFER : DHCP_ACK);
- ret.ServerAddress = IPToUINT(&e->MyIP);
- ret.LeaseTime = 3600;
- if (opt->Opcode == DHCP_INFORM)
- {
- ret.LeaseTime = 0;
- }
- ret.SubnetMask = SetIP32(255, 255, 255, 252);
- if (UnixGetDefaultDns(&default_dns) && IsZeroIp(&default_dns) == false)
- {
- ret.DnsServer = IPToUINT(&default_dns);
- ret.DnsServer2 = SetIP32(8, 8, 8, 8);
- }
- else
- {
- ret.DnsServer = SetIP32(8, 8, 8, 8);
- ret.DnsServer2 = SetIP32(8, 8, 4, 4);
- }
- ret.Gateway = IPToUINT(&e->MyIP);
- if (opt->Opcode != DHCP_INFORM)
- {
- char client_mac[MAX_SIZE];
- char client_ip[64];
- IP ips;
- BinToStr(client_mac, sizeof(client_mac), p->MacAddressSrc, 6);
- UINTToIP(&ips, ip);
- IPToStr(client_ip, sizeof(client_ip), &ips);
- Debug("IP_RAW: DHCP %s : %s given %s\n",
- ret.Opcode == DHCP_OFFER ? "DHCP_OFFER" : "DHCP_ACK",
- client_mac, client_ip);
- }
- // Build a DHCP option
- o = BuildDhcpOption(&ret);
- if (o != NULL)
- {
- BUF *b = BuildDhcpOptionsBuf(o);
- if (b != NULL)
- {
- UINT dest_ip = p->L3.IPv4Header->SrcIP;
- UINT blank_size = 128 + 64;
- UINT dhcp_packet_size;
- UINT magic = Endian32(DHCP_MAGIC_COOKIE);
- DHCPV4_HEADER *dhcp;
- void *magic_cookie_addr;
- void *buffer_addr;
- if (dest_ip == 0)
- {
- dest_ip = 0xffffffff;
- }
- // Calculate the DHCP packet size
- dhcp_packet_size = blank_size + sizeof(DHCPV4_HEADER) + sizeof(magic) + b->Size;
- if (dhcp_packet_size < DHCP_MIN_SIZE)
- {
- // Padding
- dhcp_packet_size = DHCP_MIN_SIZE;
- }
- // Create a header
- dhcp = ZeroMalloc(dhcp_packet_size);
- dhcp->OpCode = 2;
- dhcp->HardwareType = hw_type;
- dhcp->HardwareAddressSize = hw_addr_size;
- dhcp->Hops = 0;
- dhcp->TransactionId = Endian32(tran_id);
- dhcp->Seconds = 0;
- dhcp->Flags = 0;
- dhcp->YourIP = new_ip;
- dhcp->ServerIP = IPToUINT(&e->MyIP);
- Copy(dhcp->ClientMacAddress, p->MacAddressSrc, 6);
- // Calculate the address
- magic_cookie_addr = (((UCHAR *)dhcp) + sizeof(DHCPV4_HEADER) + blank_size);
- buffer_addr = ((UCHAR *)magic_cookie_addr) + sizeof(magic);
- // Magic Cookie
- Copy(magic_cookie_addr, &magic, sizeof(magic));
- // Buffer
- Copy(buffer_addr, b->Buf, b->Size);
- if (true)
- {
- UCHAR *data = ZeroMalloc(sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + dhcp_packet_size);
- IPV4_HEADER *ipv4 = (IPV4_HEADER *)(data);
- UDP_HEADER *udp = (UDP_HEADER *)(data + sizeof(IPV4_HEADER));
- Copy(data + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), dhcp, dhcp_packet_size);
- IPV4_SET_VERSION(ipv4, 4);
- IPV4_SET_HEADER_LEN(ipv4, 5);
- ipv4->TotalLength = Endian16(sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + dhcp_packet_size);
- ipv4->TimeToLive = 63;
- ipv4->Protocol = IP_PROTO_UDP;
- ipv4->SrcIP = IPToUINT(&e->MyIP);
- ipv4->DstIP = dest_ip;
- ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
- udp->SrcPort = Endian16(NAT_DHCP_SERVER_PORT);
- udp->DstPort = Endian16(NAT_DHCP_CLIENT_PORT);
- udp->PacketLength = Endian16(sizeof(UDP_HEADER) + dhcp_packet_size);
- udp->Checksum = CalcChecksumForIPv4(ipv4->SrcIP, ipv4->DstIP, IP_PROTO_UDP,
- dhcp, dhcp_packet_size, 0);
- if (udp->Checksum == 0)
- {
- udp->Checksum = 0xffff;
- }
- EthSendIpPacketInnerIpRaw(e, data, sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + dhcp_packet_size, MAC_PROTO_IPV4);
- Free(data);
- }
- // Release the memory
- Free(dhcp);
- FreeBuf(b);
- }
- FreeDhcpOptions(o);
- }
- }
- }
- Free(opt);
- }
- return ret;
- }
- // Send an IP raw packet
- void EthPutPacketLinuxIpRaw(ETH *e, void *data, UINT size)
- {
- PKT *p;
- SOCK *s = NULL;
- // Validate arguments
- if (e == NULL || data == NULL)
- {
- return;
- }
- if (size < 14 || size > MAX_PACKET_SIZE || e->RawIp_HasError)
- {
- Free(data);
- return;
- }
- p = ParsePacket(data, size);
- if (p == NULL)
- {
- Free(data);
- return;
- }
- if (p->BroadcastPacket || Cmp(p->MacAddressDest, e->RawIpMyMacAddr, 6) == 0)
- {
- if (IsMacUnicast(p->MacAddressSrc))
- {
- Copy(e->RawIpYourMacAddr, p->MacAddressSrc, 6);
- }
- }
- if (IsZero(e->RawIpYourMacAddr, 6) || IsMacUnicast(p->MacAddressSrc) == false ||
- (p->BroadcastPacket == false && Cmp(p->MacAddressDest, e->RawIpMyMacAddr, 6) != 0))
- {
- Free(data);
- FreePacket(p);
- return;
- }
- if (p->TypeL3 == L3_IPV4)
- {
- if (p->TypeL4 == L4_TCP)
- {
- if (IsZeroIP(&e->MyPhysicalIP) == false)
- {
- s = e->RawTcp;
- }
- }
- else if (p->TypeL4 == L4_UDP)
- {
- if (EthProcessIpPacketInnerIpRaw(e, p) == false)
- {
- s = e->RawUdp;
- }
- }
- else if (p->TypeL4 == L4_ICMPV4)
- {
- if (IsZeroIP(&e->MyPhysicalIP) == false)
- {
- s = e->RawIcmp;
- }
- }
- else if (p->TypeL4 == L4_FRAGMENT)
- {
- if (IsZeroIP(&e->MyPhysicalIP) == false)
- {
- s = e->RawIcmp;
- }
- }
- }
- else if (p->TypeL3 == L3_ARPV4)
- {
- EthProcessIpPacketInnerIpRaw(e, p);
- }
- if (s != NULL && p->L3.IPv4Header->DstIP != 0xffffffff && p->BroadcastPacket == false &&
- p->L3.IPv4Header->SrcIP == IPToUINT(&e->YourIP))
- {
- UCHAR *send_data = p->IPv4PayloadData;
- UCHAR *head = p->PacketData;
- UINT remove_header_size = (UINT)(send_data - head);
- if (p->PacketSize > remove_header_size)
- {
- IP dest;
- UINT send_data_size = p->PacketSize - remove_header_size;
- // checksum
- if (p->TypeL4 == L4_UDP)
- {
- p->L4.UDPHeader->Checksum = 0;
- }
- else if (p->TypeL4 == L4_TCP)
- {
- p->L4.TCPHeader->Checksum = 0;
- p->L4.TCPHeader->Checksum = CalcChecksumForIPv4(IPToUINT(&e->MyPhysicalIP),
- p->L3.IPv4Header->DstIP, IP_PROTO_TCP,
- p->L4.TCPHeader, p->IPv4PayloadSize, 0);
- }
- UINTToIP(&dest, p->L3.IPv4Header->DstIP);
- if (s->RawIP_HeaderIncludeFlag == false)
- {
- SendTo(s, &dest, 0, send_data, send_data_size);
- }
- else
- {
- IPV4_HEADER *ip = p->L3.IPv4Header;
- ip->SrcIP = IPToUINT(&e->MyPhysicalIP);
- ip->Checksum = 0;
- ip->Checksum = IpChecksum(ip, IPV4_GET_HEADER_LEN(ip) * 4);
- SendTo(s, &dest, 0, ip, ((UCHAR *)p->PacketData - (UCHAR *)ip) + p->PacketSize);
- }
- }
- }
- FreePacket(p);
- Free(data);
- }
- #endif
|