📄 pcapsend.c
字号:
// resolves an ip addr into a nexthop and index
static int ip2route(const struct in_addr *dest, DWORD *nexthop, DWORD *ifi)
{
static DWORD last_ip = 0;
static int last_nexthop;
static int last_ifi;
MIB_IPFORWARDROW route;
// check the cache
if(last_ip == dest->s_addr)
{
if(nexthop) *nexthop = last_nexthop;
if(ifi) *ifi = last_ifi;
return 0;
}
if(0 != get_best_route(dest->s_addr, &route))
return -1; // failure
last_ip = 0; // if we abort, mark as bad
// Compute the next hop
switch(route.dwForwardType)
{
case 3:
// local route; the dest is the next hop
last_nexthop = dest->s_addr;
break;
case 4:
// remote route; use the specified gateway
last_nexthop = route.dwForwardNextHop;
break;
case 2:
fatal("corrupt route table\n");
break;
default:
fatal("unknown route format %d\n", route.dwForwardType);
break;
}
// save the index
last_ifi = winif2ifi(route.dwForwardIfIndex);
// mark it valid
last_ip = dest->s_addr;
// Try to return the answer
if(nexthop) *nexthop = last_nexthop;
if(ifi) *ifi = last_ifi;
if(o.debugging > 1)
{
printf("%s is routed through ", inet_ntoa(*(struct in_addr*)&last_ip));
printf("%s\n", inet_ntoa(*(struct in_addr*)&last_nexthop));
}
return 0;
}
// The adapter cache
typedef struct _IFC_ROW {
int ifi;
LPADAPTER pAdapter;
BYTE phys[MAXLEN_PHYSADDR];
int physlen;
DWORD type;
} IFC_ROW;
static IFC_ROW last_if = {-1};
/*
static int numif = 0;
static IFC_ROW *ifcache = 0;
*/
static void cleanup_if_cache()
{
if(last_if.pAdapter)
{
PacketCloseAdapter(last_if.pAdapter);
last_if.pAdapter = 0;
}
last_if.ifi = -1;
}
static LPADAPTER if2adapter(int ifi, BYTE* phys, int *physlen, DWORD *type)
{
const WINIP_IF *ifentry;
char *name;
EnterCriticalSection(&csAdapter);
if(last_if.ifi == ifi)
{
if(last_if.physlen == -1) return 0;
if(last_if.pAdapter)
{
if(physlen && (*physlen < last_if.physlen)) return 0;
if(phys) memcpy(phys, last_if.phys, last_if.physlen);
*physlen = last_if.physlen;
if(type) *type = last_if.type;
// we do not release the CS
return last_if.pAdapter;
}
}
ifentry = ifi2ifentry(ifi);
if(!ifentry || !ifentry->pcapname)
{
LeaveCriticalSection(&csAdapter);
return 0; // Can't do this one...
}
cleanup_if_cache();
last_if.pAdapter = PacketOpenAdapter(ifentry->pcapname);
// This is required on Win9x (defaults to 0)
// It's probably a good idea on WinNT/2K
PacketSetNumWrites(last_if.pAdapter, 1);
if(!last_if.pAdapter)
{
last_if.physlen = -1;
LeaveCriticalSection(&csAdapter);
return 0;
}
last_if.physlen = ifentry->physlen;
memcpy(last_if.phys, ifentry->physaddr, ifentry->physlen);
last_if.type = ifentry->type;
last_if.ifi = ifi;
// Try to return the answer
if(physlen && (*physlen < last_if.physlen))
{
LeaveCriticalSection(&csAdapter);
return 0;
}
if(phys) memcpy(phys, last_if.phys, last_if.physlen);
*physlen = last_if.physlen;
if(type) *type = last_if.type;
// We do not leave the CS
return last_if.pAdapter;
}
static void releaseadapter()
{
LeaveCriticalSection(&csAdapter);
}
// The almighty pcapsendraw
// This is the whole point of this file :)
int pcapsendraw(const char *packet, int len,
struct sockaddr *to, int tolen)
{
struct sockaddr_in *sin = (struct sockaddr_in *) to;
int cb = 0;
int nRes, i;
DWORD nextip;
int ifi;
LPADAPTER pAdap;
BYTE myphys[MAXLEN_PHYSADDR], tphys[MAXLEN_PHYSADDR];
int physlen = MAXLEN_PHYSADDR;
DWORD type;
if(!pcapsend_inited)
fatal("pcapsendraw: pcapsend not initialized\n");
if(-1 == ip2route(&sin->sin_addr, &nextip, &ifi))
{
WSASetLastError(WSAENETUNREACH);
return -1; // no route to host
}
// check the failcache
EnterCriticalSection(&csFailCache);
for(i = 0; i < FAILCACHELEN; i++)
{
if(failcache[i].ip == nextip && failcache[i].ifi == ifi)
{
// it failed
WSASetLastError(WSAEHOSTUNREACH);
#ifdef THREAD_DEBUG
printf("sendto: autofailed %s\n", inet_ntoa(*(struct in_addr*)&failcache[i].ip));
#endif
LeaveCriticalSection(&csFailCache);
return -1;
}
}
LeaveCriticalSection(&csFailCache);
// Read the data
nRes = SearchARP(nextip, ifi, tphys, &physlen);
if(-1 == nRes)
{
// defer the send
AddPacketToQueue(packet, len, nextip, ifi);
return len; // it's in the queue, so it worked...
}
// otherwise, we have an address
pAdap = if2adapter(ifi, myphys, &physlen, &type);
if(!pAdap)
fatal("can't send to this interface\n");
realsend(pAdap, packet, len, tphys, myphys, physlen, type, ETH_IP);
releaseadapter();
return len;
}
void pcapsend_init()
{
int i, nRes;
DWORD id;
if(pcapsend_inited) return;
pcapsend_inited = 1;
if(o.debugging > 1)
printf("Initializing winpcap send support...");
for(i = 0; i < SENDQUEUE_LEN; i++)
{
Q_FREE *f;
sendqueue[i].ifi = -1;
f = (Q_FREE*)&sendqueue[i];
f->next = nextfree;
nextfree = f;
}
InitializeCriticalSection(&csQueue);
InitializeCriticalSection(&csAdapter);
InitializeCriticalSection(&csFailCache);
InitializeCriticalSection(&csArpCache);
InitializeCriticalSection(&csArpTable);
hEvWakeup = CreateEvent(0, 0, 0, 0);
hSemQueue = CreateSemaphore(0, SENDQUEUE_LEN, SENDQUEUE_LEN, 0);
// allocate the ARP cache
arpalloclen = 0;
pArpTable = (PMIB_IPNETTABLE)&i;
nRes = GetIpNetTableSafe(pArpTable, &arpalloclen, FALSE);
if(arpalloclen == 0)
{
if(o.debugging)
printf("ARP table length failure (%lu) during init -- try kludge1 :(\n", nRes);
arpalloclen = 100 * sizeof(MIB_IPNETROW) + 8;
}
// Read the data
arpalloclen += 3 * sizeof(MIB_IPNETROW);
pArpTable = (PMIB_IPNETTABLE)malloc(arpalloclen);
if(!pArpTable)
{
pcapsend_inited = 0;
fatal("out of memory\n");
}
nRes = GetIpNetTableSafe(pArpTable, &arpalloclen, TRUE);
if(nRes != NO_ERROR)
{
if(o.debugging)
printf("ARP failure (%lu) during init -- trying kludge2\n", nRes);
pArpTable->dwNumEntries = 0;
}
// Start the send thread
hThread = (HANDLE)_beginthreadex(0, 0, SendThreadProc, 0, 0, &id);
if(!hThread)
{
pcapsend_inited = 0;
fatal("failed to start thread\n");
}
atexit(pcapsend_cleanup);
pcapsend_inited = 1;
if(o.debugging > 1)
printf(" Done\n");
}
// the name cache
typedef struct _IFNAME_ROW {
int ifi;
char name[128];
DWORD ip; // This is one of the interface's IPs
DWORD type;
} IFNAME_ROW;
static IFNAME_ROW *names = 0;
static int num_names;
static void pcapsend_cleanup(void)
{
if(!pcapsend_inited)
return;
assert(!killthread);
killthread = 1;
SetEvent(hEvWakeup);
if(WAIT_TIMEOUT == WaitForSingleObject(hThread, 10000))
{
error("timed out waiting for thread exit; terminating...\n");
TerminateThread(hThread, 0);
}
CloseHandle(hEvWakeup);
CloseHandle(hThread);
CloseHandle(hSemQueue);
DeleteCriticalSection(&csQueue);
DeleteCriticalSection(&csAdapter);
DeleteCriticalSection(&csFailCache);
DeleteCriticalSection(&csArpCache);
DeleteCriticalSection(&csArpTable);
cleanup_if_cache();
if(names) free(names);
if(pArpTable) free(pArpTable);
}
// safe implementation for getbestroute
typedef DWORD (__stdcall *PGBR)(DWORD, DWORD, PMIB_IPFORWARDROW);
int get_best_route(DWORD dest, PMIB_IPFORWARDROW r)
{
static PGBR GBR = 0;
static int inited = 0;
int winif = -1, ifi = -1;
if(!inited)
{
HINSTANCE hInst = GetModuleHandle("iphlpapi.dll");
inited = 1;
if(hInst && !wo.nt4route)
GBR = (PGBR)GetProcAddress(hInst, "GetBestRoute");
if(o.debugging > 1 && !GBR)
printf("get_best_route: using NT4-compatible method\n");
}
// Find the index
if(*o.device)
{
ifi = name2ifi(o.device);
winif = ifi2winif(ifi);
if(winif == -1)
fatal("get_best_route: nonexistant interface \"%s\"\n", o.device);
}
// Can we simply redirect?
tryagain:
if(GBR)
{
DWORD source = 0;
DWORD nRes;
if(ifi != -1)
{
if(-1 == ifi2ipaddr(ifi, (struct in_addr*)&source))
source = 0; // wtf?
}
nRes = GBR(dest, source, r);
if(nRes == ERROR_CALL_NOT_IMPLEMENTED)
{
GBR = 0;
goto tryagain;
}
if(nRes != 0) return nRes;
// verify we have a good match
if(winif != -1 && r->dwForwardIfIndex != winif)
return -1;
return 0;
}
// We need to do this for real
else
{
PMIB_IPFORWARDTABLE pTable = 0;
int cb = 0;
int bestmatch = -1;
int bestmask, bestmetric;
int nRes, i;
nRes = GetIpForwardTableSafe(pTable, &cb, FALSE);
if(cb == 0) return (nRes ? nRes : -1);
cb += sizeof(MIB_IPFORWARDROW);
pTable = (PMIB_IPFORWARDTABLE)_alloca(cb);
nRes = GetIpForwardTableSafe(pTable, &cb, FALSE);
if(nRes != NO_ERROR) return nRes;
if(pTable->dwNumEntries < 1) return -1;
for(i = 0; i < pTable->dwNumEntries; i++)
{
// is it a match?
if(pTable->table[i].dwForwardDest != (dest & pTable->table[i].dwForwardMask))
continue;
if(winif != -1 && pTable->table[i].dwForwardIfIndex != winif) continue;
/* if(bestmatch == -1 || (pTable->table[i].dwForwardMask > bestmask)
|| (pTable->table[i].dwForwardMask == bestmask
&& pTable->table[i].dwForwardMetric1 < bestmetric))*/
if(bestmatch == -1 || (pTable->table[i].dwForwardMetric1 > bestmetric)
|| (pTable->table[i].dwForwardMetric1 == bestmetric
&& pTable->table[i].dwForwardMask > bestmask))
{
bestmatch = i;
bestmask = pTable->table[i].dwForwardMask;
bestmetric = pTable->table[i].dwForwardMetric1;
}
}
if(bestmatch == -1) return -1;
memcpy(r, &pTable->table[bestmatch], sizeof(MIB_IPFORWARDROW));
return 0;
}
}
// ARP cache
static void AddToARPCache(DWORD ip, int ifi, BYTE *phys, int physlen)
{
if(physlen > MAXLEN_PHYSADDR)
fatal("physical address too long!\n");
foo0("addtoarpcache: try acquire csArpCache\n");
EnterCriticalSection(&csArpCache);
foo0("addtoarpcache: acquired csArpCache\n");
arpcache[arpfirst].ifi = ifi;
arpcache[arpfirst].ip = ip;
memcpy(arpcache[arpfirst].phys, phys, physlen);
arpcache[arpfirst].physlen = physlen;
arpfirst = (arpfirst + 1) % ARPCACHELEN;
LeaveCriticalSection(&csArpCache);
}
static int lookupip(DWORD ip, DWORD ifi)
{
DWORD time = GetTickCount();
int nRes;
int low, high;
int pass = 0;
DWORD winif = ifi2winif(ifi);
EnterCriticalSection(&csArpTable);
goto pass0;
pass1:
pass = 1;
if(arprefresh)
{
// refresh
int len = arpalloclen;
#ifdef THREAD_DEBUG
printf("lookupip: refreshing ARP table\n");
#endif
arprefresh = 0;
readarp:
nRes = GetIpNetTableSafe(pArpTable, &len, TRUE);
if(nRes == ERROR_MORE_DATA)
len += 2 * sizeof(MIB_IPNETROW); // give the benefit of the doubt
if(len == arpalloclen && nRes != NO_ERROR)
{
// Windows bug -- just assume the table is empty
pArpTable->dwNumEntries = 0;
LeaveCriticalSection(&csArpTable);
return -1;
}
if(len > arpalloclen)
{
// need to try that again
free(pArpTable);
pArpTable = (PMIB_IPNETTABLE)malloc(len);
arpalloclen = len;
if(!pArpTable) fatal("out of memory\n");
goto readarp; // please don't infinite loop!
}
}
pass0:
low = 0;
high = pArpTable->dwNumEntries - 1;
while(low <= high)
{
int i = low + (high - low) / 2;
if(pArpTable->table[i].dwAddr == ip
&& pArpTable->table[i].dwType != 2)
{
// we found it
if(pArpTable->table[i].dwIndex != winif)
{
fatal("lookupip: found ip on wrong interface\n"
"e-mail amluto@hotmail.com if you think this should have worked\n");
}
LeaveCriticalSection(&csArpTable);
return i;
}
// Otherwise, we need to narrow search region
if(pArpTable->table[i].dwAddr < ip)
low = i + 1;
else high = i - 1;
}
if(pass == 0) goto pass1;
LeaveCriticalSection(&csArpTable);
return -1;
}
static int SearchARP(DWORD ip, int ifi, BYTE *phys, int *physlen)
{
int i;
foo0("searcharp: try acquire csArpCache\n");
EnterCriticalSection(&csArpCache);
foo0("searcharp: acquired csArpCache\n");
// Is it in the ARP cache?
for(i = 0; i < ARPCACHELEN; i++)
{
if(arpcache[i].ip == ip && arpcache[i].ifi == ifi)
{
// we got it!
if(*physlen < arpcache[i].physlen)
fatal("searcharp: can't return the answer\n");
memcpy(phys, arpcache[i].phys, arpcache[i].physlen);
*physlen = arpcache[i].physlen;
#ifdef THREAD_DEBUG
printf("searcharp: found %s in cache\n", inet_ntoa(*(struct in_addr*)&ip));
#endif
LeaveCriticalSection(&csArpCache);
return 0;
}
}
// else look it up
i = lookupip(ip, ifi);
LeaveCriticalSection(&csArpCache);
if(i == -1) return -1;
if(*physlen < pArpTable->table[i].dwPhysAddrLen)
fatal("insufficient space for physaddr\n");
*physlen = pArpTable->table[i].dwPhysAddrLen;
memcpy(phys, pArpTable->table[i].bPhysAddr,
pArpTable->table[i].dwPhysAddrLen);
#ifdef THREAD_DEBUG
printf("searcharp: found %s in system ARP table\n", inet_ntoa(*(struct in_addr*)&ip));
#endif
AddToARPCache(ip, ifi, phys, pArpTable->table[i].dwPhysAddrLen);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -