mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-25 15:19:53 -06:00
Split networking code into its own target (#2091)
This commit is contained in:
20
src/net/CMakeLists.txt
Normal file
20
src/net/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
add_library(net-utils STATIC
|
||||
Net.cpp
|
||||
Net_PCap.cpp
|
||||
Net_Slirp.cpp
|
||||
PacketDispatcher.cpp
|
||||
LocalMP.cpp
|
||||
)
|
||||
|
||||
target_include_directories(net-utils PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_include_directories(net-utils PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
|
||||
|
||||
option(USE_SYSTEM_LIBSLIRP "Use system libslirp instead of the bundled version" OFF)
|
||||
if (USE_SYSTEM_LIBSLIRP)
|
||||
pkg_check_modules(Slirp REQUIRED IMPORTED_TARGET slirp)
|
||||
target_link_libraries(net-utils PRIVATE PkgConfig::Slirp)
|
||||
else()
|
||||
add_subdirectory(libslirp EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(net-utils PRIVATE slirp)
|
||||
endif()
|
443
src/net/LocalMP.cpp
Normal file
443
src/net/LocalMP.cpp
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "LocalMP.h"
|
||||
#include "Platform.h"
|
||||
#include "types.h"
|
||||
|
||||
using namespace melonDS;
|
||||
using namespace melonDS::Platform;
|
||||
|
||||
using Platform::Log;
|
||||
using Platform::LogLevel;
|
||||
|
||||
namespace LocalMP
|
||||
{
|
||||
|
||||
struct MPStatusData
|
||||
{
|
||||
u16 ConnectedBitmask; // bitmask of which instances are ready to send/receive packets
|
||||
u32 PacketWriteOffset;
|
||||
u32 ReplyWriteOffset;
|
||||
u16 MPHostinst; // instance ID from which the last CMD frame was sent
|
||||
u16 MPReplyBitmask; // bitmask of which clients replied in time
|
||||
};
|
||||
|
||||
struct MPPacketHeader
|
||||
{
|
||||
u32 Magic;
|
||||
u32 SenderID;
|
||||
u32 Type; // 0=regular 1=CMD 2=reply 3=ack
|
||||
u32 Length;
|
||||
u64 Timestamp;
|
||||
};
|
||||
|
||||
const u32 kPacketQueueSize = 0x10000;
|
||||
const u32 kReplyQueueSize = 0x10000;
|
||||
const u32 kMaxFrameSize = 0x948;
|
||||
|
||||
Mutex* MPQueueLock;
|
||||
MPStatusData MPStatus;
|
||||
u8 MPPacketQueue[kPacketQueueSize];
|
||||
u8 MPReplyQueue[kReplyQueueSize];
|
||||
u32 PacketReadOffset[16];
|
||||
u32 ReplyReadOffset[16];
|
||||
|
||||
int RecvTimeout;
|
||||
|
||||
int LastHostID;
|
||||
|
||||
|
||||
Semaphore* SemPool[32];
|
||||
|
||||
void SemPoolInit()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
SemPool[i] = Semaphore_Create();
|
||||
}
|
||||
}
|
||||
|
||||
bool SemPost(int num)
|
||||
{
|
||||
Semaphore_Post(SemPool[num]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SemWait(int num, int timeout)
|
||||
{
|
||||
return Semaphore_TryWait(SemPool[num], timeout);
|
||||
}
|
||||
|
||||
void SemReset(int num)
|
||||
{
|
||||
Semaphore_Reset(SemPool[num]);
|
||||
}
|
||||
|
||||
|
||||
bool Init()
|
||||
{
|
||||
MPQueueLock = Mutex_Create();
|
||||
Mutex_Lock(MPQueueLock);
|
||||
|
||||
memset(MPPacketQueue, 0, kPacketQueueSize);
|
||||
memset(MPReplyQueue, 0, kReplyQueueSize);
|
||||
memset(&MPStatus, 0, sizeof(MPStatus));
|
||||
memset(PacketReadOffset, 0, sizeof(PacketReadOffset));
|
||||
memset(ReplyReadOffset, 0, sizeof(ReplyReadOffset));
|
||||
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
|
||||
// prepare semaphores
|
||||
// semaphores 0-15: regular frames; semaphore I is posted when instance I needs to process a new frame
|
||||
// semaphores 16-31: MP replies; semaphore I is posted when instance I needs to process a new MP reply
|
||||
|
||||
SemPoolInit();
|
||||
|
||||
LastHostID = -1;
|
||||
|
||||
Log(LogLevel::Info, "MP comm init OK\n");
|
||||
|
||||
RecvTimeout = 25;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
Semaphore_Free(SemPool[i]);
|
||||
SemPool[i] = nullptr;
|
||||
}
|
||||
|
||||
Mutex_Free(MPQueueLock);
|
||||
}
|
||||
|
||||
void SetRecvTimeout(int timeout)
|
||||
{
|
||||
RecvTimeout = timeout;
|
||||
}
|
||||
|
||||
void Begin(int inst)
|
||||
{
|
||||
Mutex_Lock(MPQueueLock);
|
||||
PacketReadOffset[inst] = MPStatus.PacketWriteOffset;
|
||||
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;
|
||||
SemReset(inst);
|
||||
SemReset(16+inst);
|
||||
MPStatus.ConnectedBitmask |= (1 << inst);
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
}
|
||||
|
||||
void End(int inst)
|
||||
{
|
||||
Mutex_Lock(MPQueueLock);
|
||||
MPStatus.ConnectedBitmask &= ~(1 << inst);
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
}
|
||||
|
||||
void FIFORead(int inst, int fifo, void* buf, int len)
|
||||
{
|
||||
u8* data;
|
||||
|
||||
u32 offset, datalen;
|
||||
if (fifo == 0)
|
||||
{
|
||||
offset = PacketReadOffset[inst];
|
||||
data = MPPacketQueue;
|
||||
datalen = kPacketQueueSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = ReplyReadOffset[inst];
|
||||
data = MPReplyQueue;
|
||||
datalen = kReplyQueueSize;
|
||||
}
|
||||
|
||||
if ((offset + len) >= datalen)
|
||||
{
|
||||
u32 part1 = datalen - offset;
|
||||
memcpy(buf, &data[offset], part1);
|
||||
memcpy(&((u8*)buf)[part1], data, len - part1);
|
||||
offset = len - part1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(buf, &data[offset], len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (fifo == 0) PacketReadOffset[inst] = offset;
|
||||
else ReplyReadOffset[inst] = offset;
|
||||
}
|
||||
|
||||
void FIFOWrite(int inst, int fifo, void* buf, int len)
|
||||
{
|
||||
u8* data;
|
||||
|
||||
u32 offset, datalen;
|
||||
if (fifo == 0)
|
||||
{
|
||||
offset = MPStatus.PacketWriteOffset;
|
||||
data = MPPacketQueue;
|
||||
datalen = kPacketQueueSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = MPStatus.ReplyWriteOffset;
|
||||
data = MPReplyQueue;
|
||||
datalen = kReplyQueueSize;
|
||||
}
|
||||
|
||||
if ((offset + len) >= datalen)
|
||||
{
|
||||
u32 part1 = datalen - offset;
|
||||
memcpy(&data[offset], buf, part1);
|
||||
memcpy(data, &((u8*)buf)[part1], len - part1);
|
||||
offset = len - part1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&data[offset], buf, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (fifo == 0) MPStatus.PacketWriteOffset = offset;
|
||||
else MPStatus.ReplyWriteOffset = offset;
|
||||
}
|
||||
|
||||
int SendPacketGeneric(int inst, u32 type, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
if (len > kMaxFrameSize)
|
||||
{
|
||||
Log(LogLevel::Warn, "wifi: attempting to send frame too big (len=%d max=%d)\n", len, kMaxFrameSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Mutex_Lock(MPQueueLock);
|
||||
|
||||
u16 mask = MPStatus.ConnectedBitmask;
|
||||
|
||||
// TODO: check if the FIFO is full!
|
||||
|
||||
MPPacketHeader pktheader;
|
||||
pktheader.Magic = 0x4946494E;
|
||||
pktheader.SenderID = inst;
|
||||
pktheader.Type = type;
|
||||
pktheader.Length = len;
|
||||
pktheader.Timestamp = timestamp;
|
||||
|
||||
type &= 0xFFFF;
|
||||
int nfifo = (type == 2) ? 1 : 0;
|
||||
FIFOWrite(inst, nfifo, &pktheader, sizeof(pktheader));
|
||||
if (len)
|
||||
FIFOWrite(inst, nfifo, packet, len);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
// NOTE: this is not guarded against, say, multiple multiplay games happening on the same machine
|
||||
// we would need to pass the packet's SenderID through the wifi module for that
|
||||
MPStatus.MPHostinst = inst;
|
||||
MPStatus.MPReplyBitmask = 0;
|
||||
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;
|
||||
SemReset(16 + inst);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
MPStatus.MPReplyBitmask |= (1 << inst);
|
||||
}
|
||||
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
|
||||
if (type == 2)
|
||||
{
|
||||
SemPost(16 + MPStatus.MPHostinst);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (mask & (1<<i))
|
||||
SemPost(i);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int RecvPacketGeneric(int inst, u8* packet, bool block, u64* timestamp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (!SemWait(inst, block ? RecvTimeout : 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Mutex_Lock(MPQueueLock);
|
||||
|
||||
MPPacketHeader pktheader;
|
||||
FIFORead(inst, 0, &pktheader, sizeof(pktheader));
|
||||
|
||||
if (pktheader.Magic != 0x4946494E)
|
||||
{
|
||||
Log(LogLevel::Warn, "PACKET FIFO OVERFLOW\n");
|
||||
PacketReadOffset[inst] = MPStatus.PacketWriteOffset;
|
||||
SemReset(inst);
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pktheader.SenderID == inst)
|
||||
{
|
||||
// skip this packet
|
||||
PacketReadOffset[inst] += pktheader.Length;
|
||||
if (PacketReadOffset[inst] >= kPacketQueueSize)
|
||||
PacketReadOffset[inst] -= kPacketQueueSize;
|
||||
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pktheader.Length)
|
||||
{
|
||||
FIFORead(inst, 0, packet, pktheader.Length);
|
||||
|
||||
if (pktheader.Type == 1)
|
||||
LastHostID = pktheader.SenderID;
|
||||
}
|
||||
|
||||
if (timestamp) *timestamp = pktheader.Timestamp;
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
return pktheader.Length;
|
||||
}
|
||||
}
|
||||
|
||||
int SendPacket(int inst, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
return SendPacketGeneric(inst, 0, packet, len, timestamp);
|
||||
}
|
||||
|
||||
int RecvPacket(int inst, u8* packet, u64* timestamp)
|
||||
{
|
||||
return RecvPacketGeneric(inst, packet, false, timestamp);
|
||||
}
|
||||
|
||||
|
||||
int SendCmd(int inst, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
return SendPacketGeneric(inst, 1, packet, len, timestamp);
|
||||
}
|
||||
|
||||
int SendReply(int inst, u8* packet, int len, u64 timestamp, u16 aid)
|
||||
{
|
||||
return SendPacketGeneric(inst, 2 | (aid<<16), packet, len, timestamp);
|
||||
}
|
||||
|
||||
int SendAck(int inst, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
return SendPacketGeneric(inst, 3, packet, len, timestamp);
|
||||
}
|
||||
|
||||
int RecvHostPacket(int inst, u8* packet, u64* timestamp)
|
||||
{
|
||||
if (LastHostID != -1)
|
||||
{
|
||||
// check if the host is still connected
|
||||
|
||||
u16 curinstmask = MPStatus.ConnectedBitmask;
|
||||
|
||||
if (!(curinstmask & (1 << LastHostID)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return RecvPacketGeneric(inst, packet, true, timestamp);
|
||||
}
|
||||
|
||||
u16 RecvReplies(int inst, u8* packets, u64 timestamp, u16 aidmask)
|
||||
{
|
||||
u16 ret = 0;
|
||||
u16 myinstmask = (1 << inst);
|
||||
u16 curinstmask;
|
||||
|
||||
curinstmask = MPStatus.ConnectedBitmask;
|
||||
|
||||
// if all clients have left: return early
|
||||
if ((myinstmask & curinstmask) == curinstmask)
|
||||
return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!SemWait(16+inst, RecvTimeout))
|
||||
{
|
||||
// no more replies available
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mutex_Lock(MPQueueLock);
|
||||
|
||||
MPPacketHeader pktheader;
|
||||
FIFORead(inst, 1, &pktheader, sizeof(pktheader));
|
||||
|
||||
if (pktheader.Magic != 0x4946494E)
|
||||
{
|
||||
Log(LogLevel::Warn, "REPLY FIFO OVERFLOW\n");
|
||||
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;
|
||||
SemReset(16+inst);
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((pktheader.SenderID == inst) || // packet we sent out (shouldn't happen, but hey)
|
||||
(pktheader.Timestamp < (timestamp - 32))) // stale packet
|
||||
{
|
||||
// skip this packet
|
||||
ReplyReadOffset[inst] += pktheader.Length;
|
||||
if (ReplyReadOffset[inst] >= kReplyQueueSize)
|
||||
ReplyReadOffset[inst] -= kReplyQueueSize;
|
||||
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pktheader.Length)
|
||||
{
|
||||
u32 aid = (pktheader.Type >> 16);
|
||||
FIFORead(inst, 1, &packets[(aid-1)*1024], pktheader.Length);
|
||||
ret |= (1 << aid);
|
||||
}
|
||||
|
||||
myinstmask |= (1 << pktheader.SenderID);
|
||||
if (((myinstmask & curinstmask) == curinstmask) ||
|
||||
((ret & aidmask) == aidmask))
|
||||
{
|
||||
// all the clients have sent their reply
|
||||
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mutex_Unlock(MPQueueLock);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
46
src/net/LocalMP.h
Normal file
46
src/net/LocalMP.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef LOCALMP_H
|
||||
#define LOCALMP_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace LocalMP
|
||||
{
|
||||
|
||||
using namespace melonDS;
|
||||
bool Init();
|
||||
void DeInit();
|
||||
|
||||
void SetRecvTimeout(int timeout);
|
||||
|
||||
void Begin(int inst);
|
||||
void End(int inst);
|
||||
|
||||
int SendPacket(int inst, u8* data, int len, u64 timestamp);
|
||||
int RecvPacket(int inst, u8* data, u64* timestamp);
|
||||
int SendCmd(int inst, u8* data, int len, u64 timestamp);
|
||||
int SendReply(int inst, u8* data, int len, u64 timestamp, u16 aid);
|
||||
int SendAck(int inst, u8* data, int len, u64 timestamp);
|
||||
int RecvHostPacket(int inst, u8* data, u64* timestamp);
|
||||
u16 RecvReplies(int inst, u8* data, u64 timestamp, u16 aidmask);
|
||||
|
||||
}
|
||||
|
||||
#endif // LOCALMP_H
|
111
src/net/Net.cpp
Normal file
111
src/net/Net.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "Net.h"
|
||||
#include "Net_PCap.h"
|
||||
#include "Net_Slirp.h"
|
||||
#include "PacketDispatcher.h"
|
||||
#include "Platform.h"
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
namespace Net
|
||||
{
|
||||
|
||||
using Platform::Log;
|
||||
using Platform::LogLevel;
|
||||
|
||||
bool Inited = false;
|
||||
bool DirectMode;
|
||||
|
||||
PacketDispatcher Dispatcher;
|
||||
|
||||
|
||||
bool Init(bool direct, const char* devicename)
|
||||
{
|
||||
if (Inited) DeInit();
|
||||
|
||||
Dispatcher.clear();
|
||||
|
||||
DirectMode = direct;
|
||||
|
||||
bool ret = false;
|
||||
if (DirectMode)
|
||||
ret = Net_PCap::Init(devicename);
|
||||
else
|
||||
ret = Net_Slirp::Init();
|
||||
|
||||
Inited = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
if (!Inited) return;
|
||||
|
||||
if (DirectMode)
|
||||
Net_PCap::DeInit();
|
||||
else
|
||||
Net_Slirp::DeInit();
|
||||
|
||||
Inited = false;
|
||||
}
|
||||
|
||||
|
||||
void RegisterInstance(int inst)
|
||||
{
|
||||
Dispatcher.registerInstance(inst);
|
||||
}
|
||||
|
||||
void UnregisterInstance(int inst)
|
||||
{
|
||||
Dispatcher.unregisterInstance(inst);
|
||||
}
|
||||
|
||||
|
||||
void RXEnqueue(const void* buf, int len)
|
||||
{
|
||||
Dispatcher.sendPacket(nullptr, 0, buf, len, 16, 0xFFFF);
|
||||
}
|
||||
|
||||
|
||||
int SendPacket(u8* data, int len, int inst)
|
||||
{
|
||||
if (DirectMode)
|
||||
return Net_PCap::SendPacket(data, len);
|
||||
else
|
||||
return Net_Slirp::SendPacket(data, len);
|
||||
}
|
||||
|
||||
int RecvPacket(u8* data, int inst)
|
||||
{
|
||||
if (DirectMode)
|
||||
Net_PCap::RecvCheck();
|
||||
else
|
||||
Net_Slirp::RecvCheck();
|
||||
|
||||
int ret = 0;
|
||||
if (!Dispatcher.recvPacket(nullptr, nullptr, data, &ret, inst))
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
45
src/net/Net.h
Normal file
45
src/net/Net.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef NET_H
|
||||
#define NET_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Net
|
||||
{
|
||||
using namespace melonDS;
|
||||
|
||||
///
|
||||
/// @param direct Whether to use direct or indirect mode
|
||||
/// @param devicename The name of the network device to use; ignored if direct is false
|
||||
/// @return true if initialization succeeded
|
||||
bool Init(bool direct, const char* devicename);
|
||||
void DeInit();
|
||||
|
||||
void RegisterInstance(int inst);
|
||||
void UnregisterInstance(int inst);
|
||||
|
||||
void RXEnqueue(const void* buf, int len);
|
||||
|
||||
int SendPacket(u8* data, int len, int inst);
|
||||
int RecvPacket(u8* data, int inst);
|
||||
|
||||
}
|
||||
|
||||
#endif // NET_H
|
379
src/net/Net_PCap.cpp
Normal file
379
src/net/Net_PCap.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <pcap/pcap.h>
|
||||
#include "Net.h"
|
||||
#include "Net_PCap.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <iphlpapi.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netinet/in.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/if_packet.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace melonDS;
|
||||
using Platform::Log;
|
||||
using Platform::LogLevel;
|
||||
|
||||
// welp
|
||||
#ifndef PCAP_OPENFLAG_PROMISCUOUS
|
||||
#define PCAP_OPENFLAG_PROMISCUOUS 1
|
||||
#endif
|
||||
|
||||
|
||||
#define DECL_PCAP_FUNC(ret, name, args, args2) \
|
||||
typedef ret (*type_##name) args; \
|
||||
type_##name ptr_##name = nullptr; \
|
||||
ret name args { return ptr_##name args2; }
|
||||
|
||||
DECL_PCAP_FUNC(int, pcap_findalldevs, (pcap_if_t** alldevs, char* errbuf), (alldevs,errbuf))
|
||||
DECL_PCAP_FUNC(void, pcap_freealldevs, (pcap_if_t* alldevs), (alldevs))
|
||||
DECL_PCAP_FUNC(pcap_t*, pcap_open_live, (const char* src, int snaplen, int flags, int readtimeout, char* errbuf), (src,snaplen,flags,readtimeout,errbuf))
|
||||
DECL_PCAP_FUNC(void, pcap_close, (pcap_t* dev), (dev))
|
||||
DECL_PCAP_FUNC(int, pcap_setnonblock, (pcap_t* dev, int nonblock, char* errbuf), (dev,nonblock,errbuf))
|
||||
DECL_PCAP_FUNC(int, pcap_sendpacket, (pcap_t* dev, const u_char* data, int len), (dev,data,len))
|
||||
DECL_PCAP_FUNC(int, pcap_dispatch, (pcap_t* dev, int num, pcap_handler callback, u_char* data), (dev,num,callback,data))
|
||||
DECL_PCAP_FUNC(const u_char*, pcap_next, (pcap_t* dev, struct pcap_pkthdr* hdr), (dev,hdr))
|
||||
|
||||
|
||||
namespace Net_PCap
|
||||
{
|
||||
|
||||
const char* PCapLibNames[] =
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
// TODO: name for npcap in non-WinPCap mode
|
||||
"wpcap.dll",
|
||||
#elif defined(__APPLE__)
|
||||
"libpcap.A.dylib",
|
||||
"libpcap.dylib",
|
||||
#else
|
||||
// Linux lib names
|
||||
"libpcap.so.1",
|
||||
"libpcap.so",
|
||||
#endif
|
||||
nullptr
|
||||
};
|
||||
|
||||
AdapterData* Adapters = nullptr;
|
||||
int NumAdapters = 0;
|
||||
|
||||
Platform::DynamicLibrary* PCapLib = nullptr;
|
||||
pcap_t* PCapAdapter = nullptr;
|
||||
AdapterData* PCapAdapterData;
|
||||
|
||||
|
||||
#define LOAD_PCAP_FUNC(sym) \
|
||||
ptr_##sym = (type_##sym)DynamicLibrary_LoadFunction(lib, #sym); \
|
||||
if (!ptr_##sym) return false;
|
||||
|
||||
bool TryLoadPCap(Platform::DynamicLibrary *lib)
|
||||
{
|
||||
LOAD_PCAP_FUNC(pcap_findalldevs)
|
||||
LOAD_PCAP_FUNC(pcap_freealldevs)
|
||||
LOAD_PCAP_FUNC(pcap_open_live)
|
||||
LOAD_PCAP_FUNC(pcap_close)
|
||||
LOAD_PCAP_FUNC(pcap_setnonblock)
|
||||
LOAD_PCAP_FUNC(pcap_sendpacket)
|
||||
LOAD_PCAP_FUNC(pcap_dispatch)
|
||||
LOAD_PCAP_FUNC(pcap_next)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitAdapterList()
|
||||
{
|
||||
NumAdapters = 0;
|
||||
|
||||
// TODO: how to deal with cases where an adapter is unplugged or changes config??
|
||||
if (!PCapLib)
|
||||
{
|
||||
PCapLib = nullptr;
|
||||
PCapAdapter = nullptr;
|
||||
|
||||
for (int i = 0; PCapLibNames[i]; i++)
|
||||
{
|
||||
Platform::DynamicLibrary* lib = Platform::DynamicLibrary_Load(PCapLibNames[i]);
|
||||
if (!lib) continue;
|
||||
|
||||
if (!TryLoadPCap(lib))
|
||||
{
|
||||
Platform::DynamicLibrary_Unload(lib);
|
||||
continue;
|
||||
}
|
||||
|
||||
Log(LogLevel::Info, "PCap: lib %s, init successful\n", PCapLibNames[i]);
|
||||
PCapLib = lib;
|
||||
break;
|
||||
}
|
||||
|
||||
if (PCapLib == nullptr)
|
||||
{
|
||||
Log(LogLevel::Error, "PCap: init failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
int ret;
|
||||
|
||||
pcap_if_t* alldevs;
|
||||
ret = pcap_findalldevs(&alldevs, errbuf);
|
||||
if (ret < 0 || alldevs == nullptr)
|
||||
{
|
||||
Log(LogLevel::Warn, "PCap: no devices available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pcap_if_t* dev = alldevs;
|
||||
while (dev) { NumAdapters++; dev = dev->next; }
|
||||
|
||||
Adapters = new AdapterData[NumAdapters];
|
||||
memset(Adapters, 0, sizeof(AdapterData)*NumAdapters);
|
||||
|
||||
AdapterData* adata = &Adapters[0];
|
||||
dev = alldevs;
|
||||
while (dev)
|
||||
{
|
||||
strncpy(adata->DeviceName, dev->name, 127);
|
||||
adata->DeviceName[127] = '\0';
|
||||
|
||||
#ifndef __WIN32__
|
||||
strncpy(adata->FriendlyName, adata->DeviceName, 127);
|
||||
adata->FriendlyName[127] = '\0';
|
||||
#endif // __WIN32__
|
||||
|
||||
dev = dev->next;
|
||||
adata++;
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
ULONG bufsize = 16384;
|
||||
IP_ADAPTER_ADDRESSES* buf = (IP_ADAPTER_ADDRESSES*)HeapAlloc(GetProcessHeap(), 0, bufsize);
|
||||
ULONG uret = GetAdaptersAddresses(AF_INET, 0, nullptr, buf, &bufsize);
|
||||
if (uret == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, buf);
|
||||
buf = (IP_ADAPTER_ADDRESSES*)HeapAlloc(GetProcessHeap(), 0, bufsize);
|
||||
uret = GetAdaptersAddresses(AF_INET, 0, nullptr, buf, &bufsize);
|
||||
}
|
||||
if (uret != ERROR_SUCCESS)
|
||||
{
|
||||
Log(LogLevel::Error, "GetAdaptersAddresses() shat itself: %08X\n", uret);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumAdapters; i++)
|
||||
{
|
||||
adata = &Adapters[i];
|
||||
IP_ADAPTER_ADDRESSES* addr = buf;
|
||||
while (addr)
|
||||
{
|
||||
if (strcmp(addr->AdapterName, &adata->DeviceName[12]))
|
||||
{
|
||||
addr = addr->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0, addr->FriendlyName, 127, adata->FriendlyName, 127, nullptr, nullptr);
|
||||
adata->FriendlyName[127] = '\0';
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0, addr->Description, 127, adata->Description, 127, nullptr, nullptr);
|
||||
adata->Description[127] = '\0';
|
||||
|
||||
if (addr->PhysicalAddressLength != 6)
|
||||
{
|
||||
Log(LogLevel::Warn, "weird MAC addr length %d for %s\n", addr->PhysicalAddressLength, addr->AdapterName);
|
||||
}
|
||||
else
|
||||
memcpy(adata->MAC, addr->PhysicalAddress, 6);
|
||||
|
||||
IP_ADAPTER_UNICAST_ADDRESS* ipaddr = addr->FirstUnicastAddress;
|
||||
while (ipaddr)
|
||||
{
|
||||
SOCKADDR* sa = ipaddr->Address.lpSockaddr;
|
||||
if (sa->sa_family == AF_INET)
|
||||
{
|
||||
struct in_addr sa4 = ((sockaddr_in*)sa)->sin_addr;
|
||||
memcpy(adata->IP_v4, &sa4, 4);
|
||||
}
|
||||
|
||||
ipaddr = ipaddr->Next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, buf);
|
||||
|
||||
#else
|
||||
|
||||
struct ifaddrs* addrs;
|
||||
if (getifaddrs(&addrs) != 0)
|
||||
{
|
||||
Log(LogLevel::Error, "getifaddrs() shat itself :(\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumAdapters; i++)
|
||||
{
|
||||
adata = &Adapters[i];
|
||||
struct ifaddrs* curaddr = addrs;
|
||||
while (curaddr)
|
||||
{
|
||||
if (strcmp(curaddr->ifa_name, adata->DeviceName))
|
||||
{
|
||||
curaddr = curaddr->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!curaddr->ifa_addr)
|
||||
{
|
||||
Log(LogLevel::Error, "Device (%s) does not have an address :/\n", curaddr->ifa_name);
|
||||
curaddr = curaddr->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
u16 af = curaddr->ifa_addr->sa_family;
|
||||
if (af == AF_INET)
|
||||
{
|
||||
struct sockaddr_in* sa = (sockaddr_in*)curaddr->ifa_addr;
|
||||
memcpy(adata->IP_v4, &sa->sin_addr, 4);
|
||||
}
|
||||
#ifdef __linux__
|
||||
else if (af == AF_PACKET)
|
||||
{
|
||||
struct sockaddr_ll* sa = (sockaddr_ll*)curaddr->ifa_addr;
|
||||
if (sa->sll_halen != 6)
|
||||
Log(LogLevel::Warn, "weird MAC length %d for %s\n", sa->sll_halen, curaddr->ifa_name);
|
||||
else
|
||||
memcpy(adata->MAC, sa->sll_addr, 6);
|
||||
}
|
||||
#else
|
||||
else if (af == AF_LINK)
|
||||
{
|
||||
struct sockaddr_dl* sa = (sockaddr_dl*)curaddr->ifa_addr;
|
||||
if (sa->sdl_alen != 6)
|
||||
Log(LogLevel::Warn, "weird MAC length %d for %s\n", sa->sdl_alen, curaddr->ifa_name);
|
||||
else
|
||||
memcpy(adata->MAC, LLADDR(sa), 6);
|
||||
}
|
||||
#endif
|
||||
curaddr = curaddr->ifa_next;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
#endif // __WIN32__
|
||||
|
||||
pcap_freealldevs(alldevs);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Init(std::string_view devicename)
|
||||
{
|
||||
if (!PCapLib) PCapAdapter = nullptr;
|
||||
if (PCapAdapter) pcap_close(PCapAdapter);
|
||||
|
||||
InitAdapterList();
|
||||
|
||||
// open pcap device
|
||||
PCapAdapterData = &Adapters[0];
|
||||
for (int i = 0; i < NumAdapters; i++)
|
||||
{
|
||||
if (!strncmp(Adapters[i].DeviceName, devicename.data(), 128))
|
||||
PCapAdapterData = &Adapters[i];
|
||||
}
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
PCapAdapter = pcap_open_live(PCapAdapterData->DeviceName, 2048, PCAP_OPENFLAG_PROMISCUOUS, 1, errbuf);
|
||||
if (!PCapAdapter)
|
||||
{
|
||||
Log(LogLevel::Error, "PCap: failed to open adapter %s\n", errbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pcap_setnonblock(PCapAdapter, 1, errbuf) < 0)
|
||||
{
|
||||
Log(LogLevel::Error, "PCap: failed to set nonblocking mode\n");
|
||||
pcap_close(PCapAdapter); PCapAdapter = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
if (PCapLib)
|
||||
{
|
||||
if (PCapAdapter)
|
||||
{
|
||||
pcap_close(PCapAdapter);
|
||||
PCapAdapter = nullptr;
|
||||
}
|
||||
|
||||
Platform::DynamicLibrary_Unload(PCapLib);
|
||||
PCapLib = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RXCallback(u_char* userdata, const struct pcap_pkthdr* header, const u_char* data)
|
||||
{
|
||||
Net::RXEnqueue(data, header->len);
|
||||
}
|
||||
|
||||
int SendPacket(u8* data, int len)
|
||||
{
|
||||
if (PCapAdapter == nullptr)
|
||||
return 0;
|
||||
|
||||
if (len > 2048)
|
||||
{
|
||||
Log(LogLevel::Error, "Net_SendPacket: error: packet too long (%d)\n", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcap_sendpacket(PCapAdapter, data, len);
|
||||
// TODO: check success
|
||||
return len;
|
||||
}
|
||||
|
||||
void RecvCheck()
|
||||
{
|
||||
if (PCapAdapter == nullptr)
|
||||
return;
|
||||
|
||||
pcap_dispatch(PCapAdapter, 1, RXCallback, nullptr);
|
||||
}
|
||||
|
||||
}
|
53
src/net/Net_PCap.h
Normal file
53
src/net/Net_PCap.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef NET_PCAP_H
|
||||
#define NET_PCAP_H
|
||||
|
||||
#include <string_view>
|
||||
#include "types.h"
|
||||
|
||||
namespace Net_PCap
|
||||
{
|
||||
|
||||
using namespace melonDS;
|
||||
struct AdapterData
|
||||
{
|
||||
char DeviceName[128];
|
||||
char FriendlyName[128];
|
||||
char Description[128];
|
||||
|
||||
u8 MAC[6];
|
||||
u8 IP_v4[4];
|
||||
};
|
||||
|
||||
|
||||
extern AdapterData* Adapters;
|
||||
extern int NumAdapters;
|
||||
|
||||
|
||||
bool InitAdapterList();
|
||||
bool Init(std::string_view devicename);
|
||||
void DeInit();
|
||||
|
||||
int SendPacket(u8* data, int len);
|
||||
void RecvCheck();
|
||||
|
||||
}
|
||||
|
||||
#endif // NET_PCAP_H
|
467
src/net/Net_Slirp.cpp
Normal file
467
src/net/Net_Slirp.cpp
Normal file
@ -0,0 +1,467 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "Net.h"
|
||||
#include "FIFO.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <libslirp.h>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
namespace Net_Slirp
|
||||
{
|
||||
|
||||
using Platform::Log;
|
||||
using Platform::LogLevel;
|
||||
|
||||
const u32 kSubnet = 0x0A400000;
|
||||
const u32 kServerIP = kSubnet | 0x01;
|
||||
const u32 kDNSIP = kSubnet | 0x02;
|
||||
const u32 kClientIP = kSubnet | 0x10;
|
||||
|
||||
const u8 kServerMAC[6] = {0x00, 0xAB, 0x33, 0x28, 0x99, 0x44};
|
||||
|
||||
FIFO<u32, (0x8000 >> 2)> RXBuffer;
|
||||
|
||||
u32 IPv4ID;
|
||||
|
||||
Slirp* Ctx = nullptr;
|
||||
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
#define poll WSAPoll
|
||||
|
||||
// https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
|
||||
|
||||
struct timespec { long tv_sec; long tv_nsec; };
|
||||
#define CLOCK_MONOTONIC 1312
|
||||
|
||||
int clock_gettime(int, struct timespec *spec)
|
||||
{
|
||||
__int64 wintime;
|
||||
GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -=116444736000000000LL; //1jan1601 to 1jan1970
|
||||
spec->tv_sec = wintime / 10000000LL; //seconds
|
||||
spec->tv_nsec = wintime % 10000000LL * 100; //nano-seconds
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // __WIN32__
|
||||
|
||||
|
||||
ssize_t SlirpCbSendPacket(const void* buf, size_t len, void* opaque)
|
||||
{
|
||||
if (len > 2048)
|
||||
{
|
||||
Log(LogLevel::Warn, "slirp: packet too big (%zu)\n", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Log(LogLevel::Debug, "slirp: response packet of %zu bytes, type %04X\n", len, ntohs(((u16*)buf)[6]));
|
||||
|
||||
Net::RXEnqueue(buf, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void SlirpCbGuestError(const char* msg, void* opaque)
|
||||
{
|
||||
Log(LogLevel::Error, "SLIRP: error: %s\n", msg);
|
||||
}
|
||||
|
||||
int64_t SlirpCbClockGetNS(void* opaque)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
|
||||
}
|
||||
|
||||
void* SlirpCbTimerNew(SlirpTimerCb cb, void* cb_opaque, void* opaque)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SlirpCbTimerFree(void* timer, void* opaque)
|
||||
{
|
||||
}
|
||||
|
||||
void SlirpCbTimerMod(void* timer, int64_t expire_time, void* opaque)
|
||||
{
|
||||
}
|
||||
|
||||
void SlirpCbRegisterPollFD(int fd, void* opaque)
|
||||
{
|
||||
Log(LogLevel::Debug, "Slirp: register poll FD %d\n", fd);
|
||||
}
|
||||
|
||||
void SlirpCbUnregisterPollFD(int fd, void* opaque)
|
||||
{
|
||||
Log(LogLevel::Debug, "Slirp: unregister poll FD %d\n", fd);
|
||||
}
|
||||
|
||||
void SlirpCbNotify(void* opaque)
|
||||
{
|
||||
Log(LogLevel::Debug, "Slirp: notify???\n");
|
||||
}
|
||||
|
||||
SlirpCb cb =
|
||||
{
|
||||
.send_packet = SlirpCbSendPacket,
|
||||
.guest_error = SlirpCbGuestError,
|
||||
.clock_get_ns = SlirpCbClockGetNS,
|
||||
.timer_new = SlirpCbTimerNew,
|
||||
.timer_free = SlirpCbTimerFree,
|
||||
.timer_mod = SlirpCbTimerMod,
|
||||
.register_poll_fd = SlirpCbRegisterPollFD,
|
||||
.unregister_poll_fd = SlirpCbUnregisterPollFD,
|
||||
.notify = SlirpCbNotify
|
||||
};
|
||||
|
||||
bool Init()
|
||||
{
|
||||
IPv4ID = 0;
|
||||
|
||||
SlirpConfig cfg;
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.version = 1;
|
||||
|
||||
cfg.in_enabled = true;
|
||||
*(u32*)&cfg.vnetwork = htonl(kSubnet);
|
||||
*(u32*)&cfg.vnetmask = htonl(0xFFFFFF00);
|
||||
*(u32*)&cfg.vhost = htonl(kServerIP);
|
||||
cfg.vhostname = "melonServer";
|
||||
*(u32*)&cfg.vdhcp_start = htonl(kClientIP);
|
||||
*(u32*)&cfg.vnameserver = htonl(kDNSIP);
|
||||
|
||||
Ctx = slirp_new(&cfg, &cb, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
if (Ctx)
|
||||
{
|
||||
slirp_cleanup(Ctx);
|
||||
Ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FinishUDPFrame(u8* data, int len)
|
||||
{
|
||||
u8* ipheader = &data[0xE];
|
||||
u8* udpheader = &data[0x22];
|
||||
|
||||
// lengths
|
||||
*(u16*)&ipheader[2] = htons(len - 0xE);
|
||||
*(u16*)&udpheader[4] = htons(len - (0xE + 0x14));
|
||||
|
||||
// IP checksum
|
||||
u32 tmp = 0;
|
||||
|
||||
for (int i = 0; i < 20; i += 2)
|
||||
tmp += ntohs(*(u16*)&ipheader[i]);
|
||||
while (tmp >> 16)
|
||||
tmp = (tmp & 0xFFFF) + (tmp >> 16);
|
||||
tmp ^= 0xFFFF;
|
||||
*(u16*)&ipheader[10] = htons(tmp);
|
||||
|
||||
// UDP checksum
|
||||
// (note: normally not mandatory, but some older sgIP versions require it)
|
||||
tmp = 0;
|
||||
tmp += ntohs(*(u16*)&ipheader[12]);
|
||||
tmp += ntohs(*(u16*)&ipheader[14]);
|
||||
tmp += ntohs(*(u16*)&ipheader[16]);
|
||||
tmp += ntohs(*(u16*)&ipheader[18]);
|
||||
tmp += ntohs(0x1100);
|
||||
tmp += (len-0x22);
|
||||
for (u8* i = udpheader; i < &udpheader[len-0x23]; i += 2)
|
||||
tmp += ntohs(*(u16*)i);
|
||||
if (len & 1)
|
||||
tmp += ntohs((u_short)udpheader[len-0x23]);
|
||||
while (tmp >> 16)
|
||||
tmp = (tmp & 0xFFFF) + (tmp >> 16);
|
||||
tmp ^= 0xFFFF;
|
||||
if (tmp == 0) tmp = 0xFFFF;
|
||||
*(u16*)&udpheader[6] = htons(tmp);
|
||||
}
|
||||
|
||||
void HandleDNSFrame(u8* data, int len)
|
||||
{
|
||||
u8* ipheader = &data[0xE];
|
||||
u8* udpheader = &data[0x22];
|
||||
u8* dnsbody = &data[0x2A];
|
||||
|
||||
u32 srcip = ntohl(*(u32*)&ipheader[12]);
|
||||
u16 srcport = ntohs(*(u16*)&udpheader[0]);
|
||||
|
||||
u16 id = ntohs(*(u16*)&dnsbody[0]);
|
||||
u16 flags = ntohs(*(u16*)&dnsbody[2]);
|
||||
u16 numquestions = ntohs(*(u16*)&dnsbody[4]);
|
||||
u16 numanswers = ntohs(*(u16*)&dnsbody[6]);
|
||||
u16 numauth = ntohs(*(u16*)&dnsbody[8]);
|
||||
u16 numadd = ntohs(*(u16*)&dnsbody[10]);
|
||||
|
||||
Log(LogLevel::Debug, "DNS: ID=%04X, flags=%04X, Q=%d, A=%d, auth=%d, add=%d\n",
|
||||
id, flags, numquestions, numanswers, numauth, numadd);
|
||||
|
||||
// for now we only take 'simple' DNS requests
|
||||
if (flags & 0x8000) return;
|
||||
if (numquestions != 1 || numanswers != 0) return;
|
||||
|
||||
u8 resp[1024];
|
||||
u8* out = &resp[0];
|
||||
|
||||
// ethernet
|
||||
memcpy(out, &data[6], 6); out += 6;
|
||||
memcpy(out, kServerMAC, 6); out += 6;
|
||||
*(u16*)out = htons(0x0800); out += 2;
|
||||
|
||||
// IP
|
||||
u8* resp_ipheader = out;
|
||||
*out++ = 0x45;
|
||||
*out++ = 0x00;
|
||||
*(u16*)out = 0; out += 2; // total length
|
||||
*(u16*)out = htons(IPv4ID); out += 2; IPv4ID++;
|
||||
*out++ = 0x00;
|
||||
*out++ = 0x00;
|
||||
*out++ = 0x80; // TTL
|
||||
*out++ = 0x11; // protocol (UDP)
|
||||
*(u16*)out = 0; out += 2; // checksum
|
||||
*(u32*)out = htonl(kDNSIP); out += 4; // source IP
|
||||
*(u32*)out = htonl(srcip); out += 4; // destination IP
|
||||
|
||||
// UDP
|
||||
u8* resp_udpheader = out;
|
||||
*(u16*)out = htons(53); out += 2; // source port
|
||||
*(u16*)out = htons(srcport); out += 2; // destination port
|
||||
*(u16*)out = 0; out += 2; // length
|
||||
*(u16*)out = 0; out += 2; // checksum
|
||||
|
||||
// DNS
|
||||
u8* resp_body = out;
|
||||
*(u16*)out = htons(id); out += 2; // ID
|
||||
*(u16*)out = htons(0x8000); out += 2; // flags
|
||||
*(u16*)out = htons(numquestions); out += 2; // num questions
|
||||
*(u16*)out = htons(numquestions); out += 2; // num answers
|
||||
*(u16*)out = 0; out += 2; // num authority
|
||||
*(u16*)out = 0; out += 2; // num additional
|
||||
|
||||
u32 curoffset = 12;
|
||||
for (u16 i = 0; i < numquestions; i++)
|
||||
{
|
||||
if (curoffset >= (len-0x2A)) return;
|
||||
|
||||
u8 bitlength = 0;
|
||||
while ((bitlength = dnsbody[curoffset++]) != 0)
|
||||
curoffset += bitlength;
|
||||
|
||||
curoffset += 4;
|
||||
}
|
||||
|
||||
u32 qlen = curoffset-12;
|
||||
if (qlen > 512) return;
|
||||
memcpy(out, &dnsbody[12], qlen); out += qlen;
|
||||
|
||||
curoffset = 12;
|
||||
for (u16 i = 0; i < numquestions; i++)
|
||||
{
|
||||
// assemble the requested domain name
|
||||
u8 bitlength = 0;
|
||||
char domainname[256] = ""; int o = 0;
|
||||
while ((bitlength = dnsbody[curoffset++]) != 0)
|
||||
{
|
||||
if ((o+bitlength) >= 255)
|
||||
{
|
||||
// welp. atleast try not to explode.
|
||||
domainname[o++] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(&domainname[o], (const char *)&dnsbody[curoffset], bitlength);
|
||||
o += bitlength;
|
||||
|
||||
curoffset += bitlength;
|
||||
if (dnsbody[curoffset] != 0)
|
||||
domainname[o++] = '.';
|
||||
else
|
||||
domainname[o++] = '\0';
|
||||
}
|
||||
|
||||
u16 type = ntohs(*(u16*)&dnsbody[curoffset]);
|
||||
u16 cls = ntohs(*(u16*)&dnsbody[curoffset+2]);
|
||||
|
||||
printf("- q%d: %04X %04X %s", i, type, cls, domainname);
|
||||
|
||||
// get answer
|
||||
struct addrinfo dns_hint;
|
||||
struct addrinfo* dns_res;
|
||||
u32 addr_res;
|
||||
|
||||
memset(&dns_hint, 0, sizeof(dns_hint));
|
||||
dns_hint.ai_family = AF_INET; // TODO: other address types (INET6, etc)
|
||||
if (getaddrinfo(domainname, "0", &dns_hint, &dns_res) == 0)
|
||||
{
|
||||
struct addrinfo* p = dns_res;
|
||||
while (p)
|
||||
{
|
||||
struct sockaddr_in* addr = (struct sockaddr_in*)p->ai_addr;
|
||||
addr_res = *(u32*)&addr->sin_addr;
|
||||
|
||||
printf(" -> %d.%d.%d.%d",
|
||||
addr_res & 0xFF, (addr_res >> 8) & 0xFF,
|
||||
(addr_res >> 16) & 0xFF, addr_res >> 24);
|
||||
|
||||
break;
|
||||
p = p->ai_next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" shat itself :(");
|
||||
addr_res = 0;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
curoffset += 4;
|
||||
|
||||
// TODO: betterer support
|
||||
// (under which conditions does the C00C marker work?)
|
||||
*(u16*)out = htons(0xC00C); out += 2;
|
||||
*(u16*)out = htons(type); out += 2;
|
||||
*(u16*)out = htons(cls); out += 2;
|
||||
*(u32*)out = htonl(3600); out += 4; // TTL (hardcoded for now)
|
||||
*(u16*)out = htons(4); out += 2; // address length
|
||||
*(u32*)out = addr_res; out += 4; // address
|
||||
}
|
||||
|
||||
u32 framelen = (u32)(out - &resp[0]);
|
||||
if (framelen & 1) { *out++ = 0; framelen++; }
|
||||
FinishUDPFrame(resp, framelen);
|
||||
|
||||
Net::RXEnqueue(resp, framelen);
|
||||
}
|
||||
|
||||
int SendPacket(u8* data, int len)
|
||||
{
|
||||
if (!Ctx) return 0;
|
||||
|
||||
if (len > 2048)
|
||||
{
|
||||
Log(LogLevel::Error, "Net_SendPacket: error: packet too long (%d)\n", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 ethertype = ntohs(*(u16*)&data[0xC]);
|
||||
|
||||
if (ethertype == 0x800)
|
||||
{
|
||||
u8 protocol = data[0x17];
|
||||
if (protocol == 0x11) // UDP
|
||||
{
|
||||
u16 dstport = ntohs(*(u16*)&data[0x24]);
|
||||
if (dstport == 53 && htonl(*(u32*)&data[0x1E]) == kDNSIP) // DNS
|
||||
{
|
||||
HandleDNSFrame(data, len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slirp_input(Ctx, data, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
const int PollListMax = 64;
|
||||
struct pollfd PollList[PollListMax];
|
||||
int PollListSize;
|
||||
|
||||
int SlirpCbAddPoll(int fd, int events, void* opaque)
|
||||
{
|
||||
if (PollListSize >= PollListMax)
|
||||
{
|
||||
Log(LogLevel::Error, "slirp: POLL LIST FULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int idx = PollListSize++;
|
||||
|
||||
u16 evt = 0;
|
||||
|
||||
if (events & SLIRP_POLL_IN) evt |= POLLIN;
|
||||
if (events & SLIRP_POLL_OUT) evt |= POLLWRNORM;
|
||||
|
||||
#ifndef __WIN32__
|
||||
// CHECKME
|
||||
if (events & SLIRP_POLL_PRI) evt |= POLLPRI;
|
||||
if (events & SLIRP_POLL_ERR) evt |= POLLERR;
|
||||
if (events & SLIRP_POLL_HUP) evt |= POLLHUP;
|
||||
#endif // !__WIN32__
|
||||
|
||||
PollList[idx].fd = fd;
|
||||
PollList[idx].events = evt;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int SlirpCbGetREvents(int idx, void* opaque)
|
||||
{
|
||||
if (idx < 0 || idx >= PollListSize)
|
||||
return 0;
|
||||
|
||||
u16 evt = PollList[idx].revents;
|
||||
int ret = 0;
|
||||
|
||||
if (evt & POLLIN) ret |= SLIRP_POLL_IN;
|
||||
if (evt & POLLWRNORM) ret |= SLIRP_POLL_OUT;
|
||||
if (evt & POLLPRI) ret |= SLIRP_POLL_PRI;
|
||||
if (evt & POLLERR) ret |= SLIRP_POLL_ERR;
|
||||
if (evt & POLLHUP) ret |= SLIRP_POLL_HUP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RecvCheck()
|
||||
{
|
||||
if (!Ctx) return;
|
||||
|
||||
//if (PollListSize > 0)
|
||||
{
|
||||
u32 timeout = 0;
|
||||
PollListSize = 0;
|
||||
slirp_pollfds_fill(Ctx, &timeout, SlirpCbAddPoll, nullptr);
|
||||
int res = poll(PollList, PollListSize, timeout);
|
||||
slirp_pollfds_poll(Ctx, res<0, SlirpCbGetREvents, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
36
src/net/Net_Slirp.h
Normal file
36
src/net/Net_Slirp.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef NET_SLIRP_H
|
||||
#define NET_SLIRP_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Net_Slirp
|
||||
{
|
||||
using namespace melonDS;
|
||||
|
||||
bool Init();
|
||||
void DeInit();
|
||||
|
||||
int SendPacket(u8* data, int len);
|
||||
void RecvCheck();
|
||||
|
||||
}
|
||||
|
||||
#endif // NET_SLIRP_H
|
162
src/net/PacketDispatcher.cpp
Normal file
162
src/net/PacketDispatcher.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "PacketDispatcher.h"
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
struct PacketHeader
|
||||
{
|
||||
u32 magic;
|
||||
u32 senderID;
|
||||
u32 headerLength;
|
||||
u32 dataLength;
|
||||
};
|
||||
|
||||
const u32 kPacketMagic = 0x4B504C4D;
|
||||
|
||||
|
||||
PacketDispatcher::PacketDispatcher() : mutex(Platform::Mutex_Create())
|
||||
{
|
||||
instanceMask = 0;
|
||||
memset(packetQueues, 0, sizeof(packetQueues));
|
||||
}
|
||||
|
||||
PacketDispatcher::~PacketDispatcher()
|
||||
{
|
||||
Platform::Mutex_Free(mutex);
|
||||
}
|
||||
|
||||
|
||||
void PacketDispatcher::registerInstance(int inst)
|
||||
{
|
||||
Mutex_Lock(mutex);
|
||||
|
||||
instanceMask |= (1 << inst);
|
||||
packetQueues[inst] = new PacketQueue();
|
||||
|
||||
Mutex_Unlock(mutex);
|
||||
}
|
||||
|
||||
void PacketDispatcher::unregisterInstance(int inst)
|
||||
{
|
||||
Mutex_Lock(mutex);
|
||||
|
||||
instanceMask &= ~(1 << inst);
|
||||
delete packetQueues[inst];
|
||||
|
||||
Mutex_Unlock(mutex);
|
||||
}
|
||||
|
||||
|
||||
void PacketDispatcher::clear()
|
||||
{
|
||||
Mutex_Lock(mutex);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (!(instanceMask & (1 << i)))
|
||||
continue;
|
||||
|
||||
PacketQueue* queue = packetQueues[i];
|
||||
queue->Clear();
|
||||
}
|
||||
Mutex_Unlock(mutex);
|
||||
}
|
||||
|
||||
|
||||
void PacketDispatcher::sendPacket(const void* header, int headerlen, const void* data, int datalen, int sender, u16 recv_mask)
|
||||
{
|
||||
if (!header) headerlen = 0;
|
||||
if (!data) datalen = 0;
|
||||
if ((!headerlen) && (!datalen)) return;
|
||||
if ((sizeof(PacketHeader) + headerlen + datalen) >= 0x8000) return;
|
||||
if (sender < 0 || sender > 16) return;
|
||||
|
||||
recv_mask &= instanceMask;
|
||||
if (sender < 16) recv_mask &= ~(1 << sender);
|
||||
if (!recv_mask) return;
|
||||
|
||||
PacketHeader phdr;
|
||||
phdr.magic = kPacketMagic;
|
||||
phdr.senderID = sender;
|
||||
phdr.headerLength = headerlen;
|
||||
phdr.dataLength = datalen;
|
||||
|
||||
int totallen = sizeof(phdr) + headerlen + datalen;
|
||||
|
||||
Mutex_Lock(mutex);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (!(recv_mask & (1 << i)))
|
||||
continue;
|
||||
|
||||
PacketQueue* queue = packetQueues[i];
|
||||
|
||||
// if we run out of space: discard old packets
|
||||
while (!queue->CanFit(totallen))
|
||||
{
|
||||
PacketHeader tmp;
|
||||
queue->Read(&tmp, sizeof(tmp));
|
||||
queue->Skip(tmp.headerLength + tmp.dataLength);
|
||||
}
|
||||
|
||||
queue->Write(&phdr, sizeof(phdr));
|
||||
if (headerlen) queue->Write(header, headerlen);
|
||||
if (datalen) queue->Write(data, datalen);
|
||||
}
|
||||
Mutex_Unlock(mutex);
|
||||
}
|
||||
|
||||
bool PacketDispatcher::recvPacket(void *header, int *headerlen, void *data, int *datalen, int receiver)
|
||||
{
|
||||
if ((!header) && (!data)) return false;
|
||||
if (receiver < 0 || receiver > 15) return false;
|
||||
|
||||
Mutex_Lock(mutex);
|
||||
PacketQueue* queue = packetQueues[receiver];
|
||||
|
||||
PacketHeader phdr;
|
||||
if (!queue->Read(&phdr, sizeof(phdr)))
|
||||
{
|
||||
Mutex_Unlock(mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (phdr.magic != kPacketMagic)
|
||||
{
|
||||
Mutex_Unlock(mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (phdr.headerLength)
|
||||
{
|
||||
if (headerlen) *headerlen = phdr.headerLength;
|
||||
if (header) queue->Read(header, phdr.headerLength);
|
||||
else queue->Skip(phdr.headerLength);
|
||||
}
|
||||
|
||||
if (phdr.dataLength)
|
||||
{
|
||||
if (datalen) *datalen = phdr.dataLength;
|
||||
if (data) queue->Read(data, phdr.dataLength);
|
||||
else queue->Skip(phdr.dataLength);
|
||||
}
|
||||
|
||||
Mutex_Unlock(mutex);
|
||||
return true;
|
||||
}
|
48
src/net/PacketDispatcher.h
Normal file
48
src/net/PacketDispatcher.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef PACKETDISPATCHER_H
|
||||
#define PACKETDISPATCHER_H
|
||||
|
||||
#include "Platform.h"
|
||||
#include "types.h"
|
||||
#include "FIFO.h"
|
||||
|
||||
using PacketQueue = melonDS::RingBuffer<0x8000>;
|
||||
|
||||
class PacketDispatcher
|
||||
{
|
||||
public:
|
||||
PacketDispatcher();
|
||||
~PacketDispatcher();
|
||||
|
||||
void registerInstance(int inst);
|
||||
void unregisterInstance(int inst);
|
||||
|
||||
void clear();
|
||||
|
||||
void sendPacket(const void* header, int headerlen, const void* data, int datalen, int sender, melonDS::u16 recv_mask);
|
||||
bool recvPacket(void* header, int* headerlen, void* data, int* datalen, int receiver);
|
||||
|
||||
private:
|
||||
melonDS::Platform::Mutex* mutex;
|
||||
melonDS::u16 instanceMask;
|
||||
PacketQueue* packetQueues[16];
|
||||
};
|
||||
|
||||
#endif // PACKETDISPATCHER_H
|
58
src/net/libslirp/.clang-format
vendored
Normal file
58
src/net/libslirp/.clang-format
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
---
|
||||
Language: Cpp
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false # although we like it, it creates churn
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false # churn
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
|
||||
MacroBlockEnd: '.*_END$'
|
||||
MaxEmptyLinesToKeep: 2
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
UseTab: Never
|
||||
...
|
11
src/net/libslirp/.gitignore
vendored
Normal file
11
src/net/libslirp/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
*.[aod]
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.lib
|
||||
*.obj
|
||||
/build/
|
||||
/TAGS
|
||||
/cscope*
|
||||
/src/libslirp-version.h
|
||||
/tags
|
110
src/net/libslirp/.gitlab-ci.yml
vendored
Normal file
110
src/net/libslirp/.gitlab-ci.yml
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
image: fedora:latest
|
||||
|
||||
variables:
|
||||
DEPS: meson ninja-build
|
||||
gcc libasan liblsan libubsan pkg-config glib2-devel
|
||||
mingw64-gcc mingw64-pkg-config mingw64-glib2
|
||||
clang-analyzer git-core
|
||||
|
||||
before_script:
|
||||
- dnf install -y $DEPS
|
||||
- git fetch --tags https://gitlab.freedesktop.org/slirp/libslirp.git
|
||||
- git describe
|
||||
|
||||
build:
|
||||
script:
|
||||
- meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||
- ninja -C build
|
||||
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||
- ninja -C build scan-build
|
||||
|
||||
build-asan:
|
||||
script:
|
||||
- CFLAGS=-fsanitize=address meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||
- ninja -C build
|
||||
- (cd build && ASAN_OPTIONS=detect_leaks=0 meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||
|
||||
build-lsan:
|
||||
script:
|
||||
- CFLAGS=-fsanitize=leak meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||
- ninja -C build
|
||||
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||
|
||||
build-usan:
|
||||
script:
|
||||
- CFLAGS=-fsanitize=undefined meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||
- ninja -C build
|
||||
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||
|
||||
fuzz:
|
||||
parallel:
|
||||
matrix:
|
||||
- TARGET: [arp, ip-header, udp, udp-h, tftp, dhcp, icmp, tcp, tcp-h, ndp, ip6-header, udp6, udp6-h, tftp6, icmp6, tcp6, tcp6-h]
|
||||
script:
|
||||
- CC=clang CXX=clang++ meson build -Dllvm-fuzz=true || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||
- ninja -C build
|
||||
- build/fuzzing/fuzz-$TARGET -seed=1234 -runs=1000000 fuzzing/IN_$TARGET
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- crash-*
|
||||
- leak-*
|
||||
- oom-*
|
||||
- timeout-*
|
||||
|
||||
build-mingw64:
|
||||
script:
|
||||
- (mkdir buildw && cd buildw && mingw64-meson --werror) || (cat buildw/meson-logs/meson-log.txt && exit 1)
|
||||
- ninja -C buildw
|
||||
|
||||
Coverity:
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- coverity
|
||||
script:
|
||||
- dnf update -y
|
||||
- dnf install -y curl clang
|
||||
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||
- CC=clang meson build
|
||||
- cov-analysis-linux64-*/bin/cov-build --dir cov-int ninja -C build
|
||||
- tar cfz cov-int.tar.gz cov-int
|
||||
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
|
||||
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID "
|
||||
|
||||
integration-slirp4netns:
|
||||
variables:
|
||||
SLIRP4NETNS_VERSION: "v1.1.12"
|
||||
# Consumed by `make benchmark`
|
||||
BENCHMARK_IPERF3_DURATION: "10"
|
||||
script:
|
||||
# Install libslirp
|
||||
- meson build
|
||||
- ninja -C build install
|
||||
# Register the path of libslirp.so.0
|
||||
- echo /usr/local/lib64 >/etc/ld.so.conf.d/libslirp.conf
|
||||
- ldconfig
|
||||
# Install the dependencies of slirp4netns and its test suite
|
||||
# TODO: install udhcpc for `slirp4netns/tests/test-slirp4netns-dhcp.sh` (currently skipped, due to lack of udhcpc)
|
||||
- dnf install -y autoconf automake findutils iperf3 iproute iputils jq libcap-devel libseccomp-devel nmap-ncat util-linux
|
||||
# Check whether the runner environment is configured correctly
|
||||
- unshare -rn true || (echo Make sure you have relaxed seccomp and appamor && exit 1)
|
||||
- unshare -rn ip tap add tap0 mode tap || (echo Make sure you have /dev/net/tun && exit 1)
|
||||
# Install slirp4netns
|
||||
- git clone https://github.com/rootless-containers/slirp4netns -b "${SLIRP4NETNS_VERSION}"
|
||||
- cd slirp4netns
|
||||
- ./autogen.sh
|
||||
- ./configure
|
||||
- make
|
||||
- make install
|
||||
- slirp4netns --version
|
||||
# Run slirp4netns integration test
|
||||
- make distcheck || (cat $(find . -name 'test-suite.log' ) && exit 1)
|
||||
# Run benchmark test to ensure that libslirp can actually handle packets, with several MTU configurations
|
||||
- make benchmark MTU=1500
|
||||
- make benchmark MTU=512
|
||||
- make benchmark MTU=65520
|
3
src/net/libslirp/.gitpublish
vendored
Normal file
3
src/net/libslirp/.gitpublish
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[gitpublishprofile "default"]
|
||||
base = master
|
||||
to = slirp@lists.freedesktop.org
|
238
src/net/libslirp/CHANGELOG.md
vendored
Normal file
238
src/net/libslirp/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [4.8.0] - TODO
|
||||
|
||||
## Security
|
||||
|
||||
- tcp: Fix testing for last fragment
|
||||
- tftp: Fix use-after-free
|
||||
|
||||
### Added
|
||||
|
||||
- Add support for Haiku !123
|
||||
- ncsi: Add manufacturer's ID !122
|
||||
- ncsi: Add Get Version ID command !122
|
||||
- ncsi: Add out-of-band ethernet address !125
|
||||
- ncsi: Add Mellanox Get Mac Address handler !125
|
||||
- icmp6: Add echo request forwarding support
|
||||
- Add fuzzing infrastructure
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix missing cleanups
|
||||
- windows: Build fixes
|
||||
- ipv6: Use target address from Neighbor Advertisement !129
|
||||
- dns: Reject domain-search when any entry ends with ".."
|
||||
- dns: Use localhost as dns when /etc/resolv.conf empty !130
|
||||
- icmp: Handle ICMP packets as IPPROTO_IP on BSD !133
|
||||
- eth: pad ethernet frames to 60 bytes #34
|
||||
|
||||
### Removed
|
||||
|
||||
- windows: Bump the minimum Windows version to Windows 7
|
||||
|
||||
## [4.7.0] - 2022-04-26
|
||||
|
||||
### Added
|
||||
|
||||
- Allow disabling the internal DHCP server !22
|
||||
- icmp: Support falling back on trying a SOCK_RAW socket !92
|
||||
- Support Unix sockets in hostfwd !103
|
||||
- IPv6 DNS proxying support !110
|
||||
- bootp: add support for UEFI HTTP boot !111
|
||||
- New callback that supports CFI better !117
|
||||
|
||||
### Fixed
|
||||
|
||||
- dhcp: Always send DHCP_OPT_LEN bytes in options !97
|
||||
- Fix Haiku build !98 !99
|
||||
- Fix memory leak when using libresolv !100
|
||||
- Ensure sin6_scope_id is zero for global addresses !102
|
||||
- resolv: fix IPv6 resolution on Darwin !104
|
||||
- socket: Initialize so_type in socreate !109
|
||||
- Handle ECONNABORTED from recv !116
|
||||
|
||||
## [4.6.1] - 2021-06-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix DHCP regression introduced in 4.6.0. !95
|
||||
|
||||
## [4.6.0] - 2021-06-14
|
||||
|
||||
### Added
|
||||
|
||||
- mbuf: Add debugging helpers for allocation. !90
|
||||
|
||||
### Changed
|
||||
|
||||
- Revert "Set macOS deployment target to macOS 10.4". !93
|
||||
|
||||
### Fixed
|
||||
|
||||
- mtod()-related buffer overflows (CVE-2021-3592 #44, CVE-2021-3593 #45,
|
||||
CVE-2021-3594 #47, CVE-2021-3595 #46).
|
||||
- poll_fd: add missing fd registration for UDP and ICMP
|
||||
- ncsi: make ncsi_calculate_checksum work with unaligned data. !89
|
||||
- Various typos and doc fixes. !88
|
||||
|
||||
## [4.5.0] - 2021-05-18
|
||||
|
||||
### Added
|
||||
|
||||
- IPv6 forwarding. !62 !75 !77
|
||||
- slirp_neighbor_info() to dump the ARP/NDP tables. !71
|
||||
|
||||
### Changed
|
||||
|
||||
- Lazy guest address resolution for IPv6. !81
|
||||
- Improve signal handling when spawning a child. !61
|
||||
- Set macOS deployment target to macOS 10.4. !72
|
||||
- slirp_add_hostfwd: Ensure all error paths set errno. !80
|
||||
- More API documentation.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Assertion failure on unspecified IPv6 address. !86
|
||||
- Disable polling for PRI on MacOS, fixing some closing streams issues. !73
|
||||
- Various memory leak fixes on fastq/batchq. !68
|
||||
- Memory leak on IPv6 fast-send. !67
|
||||
- Slow socket response on Windows. !64
|
||||
- Misc build and code cleanups. !60 !63 !76 !79 !84
|
||||
|
||||
## [4.4.0] - 2020-12-02
|
||||
|
||||
### Added
|
||||
|
||||
- udp, udp6, icmp: handle TTL value. !48
|
||||
- Enable forwarding ICMP errors. !49
|
||||
- Add DNS resolving for iOS. !54
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve meson subproject() support. !53
|
||||
- Removed Makefile-based build system. !56
|
||||
|
||||
### Fixed
|
||||
|
||||
- socket: consume empty packets. !55
|
||||
- check pkt_len before reading protocol header (CVE-2020-29129). !57
|
||||
- ip_stripoptions use memmove (fixes undefined behaviour). !47
|
||||
- various Coverity-related changes/fixes.
|
||||
|
||||
## [4.3.1] - 2020-07-08
|
||||
|
||||
### Changed
|
||||
|
||||
- A silent truncation could occur in `slirp_fmt()`, which will now print a
|
||||
critical message. See also #22.
|
||||
|
||||
### Fixed
|
||||
|
||||
- CVE-2020-10756 - Drop bogus IPv6 messages that could lead to data leakage.
|
||||
See !44 and !42.
|
||||
- Fix win32 builds by using the SLIRP_PACKED definition.
|
||||
- Various coverity scan errors fixed. !41
|
||||
- Fix new GCC warnings. !43
|
||||
|
||||
## [4.3.0] - 2020-04-22
|
||||
|
||||
### Added
|
||||
|
||||
- `SLIRP_VERSION_STRING` macro, with the git sha suffix when building from git
|
||||
- `SlirpConfig.disable_dns`, to disable DNS redirection #16
|
||||
|
||||
### Changed
|
||||
|
||||
- `slirp_version_string()` now has the git sha suffix when building form git
|
||||
- Limit DNS redirection to port 53 #16
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix build regression with mingw & NetBSD
|
||||
- Fix use-afte-free in `ip_reass()` (CVE-2020-1983)
|
||||
|
||||
## [4.2.0] - 2020-03-17
|
||||
|
||||
### Added
|
||||
|
||||
- New API function `slirp_add_unix`: add a forward rule to a Unix socket.
|
||||
- New API function `slirp_remove_guestfwd`: remove a forward rule previously
|
||||
added by `slirp_add_exec`, `slirp_add_unix` or `slirp_add_guestfwd`
|
||||
- New `SlirpConfig.outbound_addr{,6}` fields to bind output socket to a
|
||||
specific address
|
||||
|
||||
### Changed
|
||||
|
||||
- socket: do not fallback on host loopback if `get_dns_addr()` failed
|
||||
or the address is in slirp network
|
||||
|
||||
### Fixed
|
||||
|
||||
- ncsi: fix checksum OOB memory access
|
||||
- `tcp_emu()`: fix OOB accesses
|
||||
- tftp: restrict relative path access
|
||||
- state: fix loading of guestfwd state
|
||||
|
||||
## [4.1.0] - 2019-12-02
|
||||
|
||||
### Added
|
||||
|
||||
- The `slirp_new()` API, simpler and more extensible than `slirp_init()`.
|
||||
- Allow custom MTU configuration.
|
||||
- Option to disable host loopback connections.
|
||||
- CI now runs scan-build too.
|
||||
|
||||
### Changed
|
||||
|
||||
- Disable `tcp_emu()` by default. `tcp_emu()` is known to have caused
|
||||
several CVEs, and not useful today in most cases. The feature can
|
||||
be still enabled by setting `SlirpConfig.enable_emu` to true.
|
||||
- meson build system is now `subproject()` friendly.
|
||||
- Replace remaining `malloc()`/`free()` with glib (which aborts on OOM)
|
||||
- Various code cleanups.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- The `slirp_init()` API.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `getpeername()` error after `shutdown(SHUT_WR)`.
|
||||
- Exec forward: correctly parse command lines that contain spaces.
|
||||
- Allow 0.0.0.0 destination address.
|
||||
- Make host receive broadcast packets.
|
||||
- Various memory related fixes (heap overflow, leaks, NULL
|
||||
dereference).
|
||||
- Compilation warnings, dead code.
|
||||
|
||||
## [4.0.0] - 2019-05-24
|
||||
|
||||
### Added
|
||||
|
||||
- Installable as a shared library.
|
||||
- meson build system
|
||||
(& make build system for in-tree QEMU integration)
|
||||
|
||||
### Changed
|
||||
|
||||
- Standalone project, removing any QEMU dependency.
|
||||
- License clarifications.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.8.0...master
|
||||
[4.8.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.7.0...v4.8.0
|
||||
[4.7.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.1...v4.7.0
|
||||
[4.6.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.0...v4.6.1
|
||||
[4.6.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.5.0...v4.6.0
|
||||
[4.5.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.4.0...v4.5.0
|
||||
[4.4.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.1...v4.4.0
|
||||
[4.3.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.0...v4.3.1
|
||||
[4.3.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.2.0...v4.3.0
|
||||
[4.2.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...v4.2.0
|
||||
[4.1.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.0.0...v4.1.0
|
||||
[4.0.0]: https://gitlab.freedesktop.org/slirp/libslirp/commits/v4.0.0
|
67
src/net/libslirp/CMakeLists.txt
vendored
Normal file
67
src/net/libslirp/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(libslirp VERSION 4.8.0 LANGUAGES C)
|
||||
|
||||
set(SLIRP_MAJOR_VERSION "${libslirp_VERSION_MAJOR}")
|
||||
set(SLIRP_MINOR_VERSION "${libslirp_VERSION_MINOR}")
|
||||
set(SLIRP_MICRO_VERSION "${libslirp_VERSION_PATCH}")
|
||||
set(SLIRP_VERSION_STRING "\"${libslirp_VERSION}\"")
|
||||
|
||||
set(SOURCES
|
||||
src/arp_table.c
|
||||
src/bootp.c
|
||||
src/cksum.c
|
||||
src/dhcpv6.c
|
||||
src/dnssearch.c
|
||||
src/if.c
|
||||
src/ip6_icmp.c
|
||||
src/ip6_input.c
|
||||
src/ip6_output.c
|
||||
src/ip_icmp.c
|
||||
src/ip_input.c
|
||||
src/ip_output.c
|
||||
src/mbuf.c
|
||||
src/misc.c
|
||||
src/ncsi.c
|
||||
src/ndp_table.c
|
||||
src/sbuf.c
|
||||
src/slirp.c
|
||||
src/socket.c
|
||||
src/state.c
|
||||
src/stream.c
|
||||
src/tcp_input.c
|
||||
src/tcp_output.c
|
||||
src/tcp_subr.c
|
||||
src/tcp_timer.c
|
||||
src/tftp.c
|
||||
src/udp6.c
|
||||
src/udp.c
|
||||
src/util.c
|
||||
src/version.c
|
||||
src/vmstate.c
|
||||
|
||||
# glib shim
|
||||
glib/glib.c
|
||||
)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/libslirp-version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/libslirp-version.h")
|
||||
|
||||
add_library(slirp STATIC ${SOURCES})
|
||||
target_compile_definitions(slirp PUBLIC LIBSLIRP_STATIC_BUILD)
|
||||
|
||||
target_include_directories(slirp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/glib")
|
||||
target_include_directories(slirp PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_include_directories(slirp PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
target_compile_definitions(slirp PRIVATE BUILDING_LIBSLIRP)
|
||||
target_compile_definitions(slirp PRIVATE "G_LOG_DOMAIN=\"Slirp\"")
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(slirp PRIVATE ws2_32 iphlpapi)
|
||||
elseif(HAIKU)
|
||||
target_Link_libraries(slirp PRIVATE network)
|
||||
elseif(APPLE)
|
||||
target_link_libraries(slirp PRIVATE resolv)
|
||||
else()
|
||||
set_source_files_properties(glib/glib.c PROPERTIES COMPILE_FLAGS -fvisibility=hidden)
|
||||
endif()
|
62
src/net/libslirp/COPYRIGHT
vendored
Normal file
62
src/net/libslirp/COPYRIGHT
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
Slirp was written by Danny Gasparovski.
|
||||
Copyright (c), 1995,1996 All Rights Reserved.
|
||||
|
||||
Slirp is free software; "free" as in you don't have to pay for it, and you
|
||||
are free to do whatever you want with it. I do not accept any donations,
|
||||
monetary or otherwise, for Slirp. Instead, I would ask you to pass this
|
||||
potential donation to your favorite charity. In fact, I encourage
|
||||
*everyone* who finds Slirp useful to make a small donation to their
|
||||
favorite charity (for example, GreenPeace). This is not a requirement, but
|
||||
a suggestion from someone who highly values the service they provide.
|
||||
|
||||
The copyright terms and conditions:
|
||||
|
||||
---BEGIN---
|
||||
|
||||
Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
---END---
|
||||
|
||||
This basically means you can do anything you want with the software, except
|
||||
1) call it your own, and 2) claim warranty on it. There is no warranty for
|
||||
this software. None. Nada. If you lose a million dollars while using
|
||||
Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***.
|
||||
|
||||
If these conditions cannot be met due to legal restrictions (E.g. where it
|
||||
is against the law to give out Software without warranty), you must cease
|
||||
using the software and delete all copies you have.
|
||||
|
||||
Slirp uses code that is copyrighted by the following people/organizations:
|
||||
|
||||
Juha Pirkola.
|
||||
Gregory M. Christy.
|
||||
The Regents of the University of California.
|
||||
Carnegie Mellon University.
|
||||
The Australian National University.
|
||||
RSA Data Security, Inc.
|
||||
|
||||
Please read the top of each source file for the details on the various
|
||||
copyrights.
|
60
src/net/libslirp/README.md
vendored
Normal file
60
src/net/libslirp/README.md
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
# libslirp
|
||||
|
||||
libslirp is a user-mode networking library used by virtual machines,
|
||||
containers or various tools.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
A C compiler, meson and glib2 development libraries.
|
||||
|
||||
(see also [.gitlab-ci.yml](.gitlab-ci.yml) DEPS variable for the list
|
||||
of dependencies on Fedora)
|
||||
|
||||
### Building
|
||||
|
||||
You may build and install the shared library with meson:
|
||||
|
||||
``` sh
|
||||
meson build
|
||||
ninja -C build install
|
||||
```
|
||||
And configure QEMU with --enable-slirp=system to link against it.
|
||||
|
||||
(QEMU may build with the submodule static library using --enable-slirp=git)
|
||||
|
||||
### Testing
|
||||
|
||||
Unfortunately, there are no automated tests available.
|
||||
|
||||
You may run QEMU ``-net user`` linked with your development version.
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to open issues on the [project
|
||||
issues](https://gitlab.freedesktop.org/slirp/libslirp/issues) page.
|
||||
|
||||
You may clone the [gitlab
|
||||
project](https://gitlab.freedesktop.org/slirp/libslirp) and create a
|
||||
merge request.
|
||||
|
||||
Contributing with gitlab allows gitlab workflow, tracking issues,
|
||||
running CI etc.
|
||||
|
||||
Alternatively, you may send patches to slirp@lists.freedesktop.org
|
||||
mailing list.
|
||||
|
||||
## Versioning
|
||||
|
||||
We intend to use [libtool's
|
||||
versioning](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
|
||||
for the shared libraries and use [SemVer](http://semver.org/) for
|
||||
project versions.
|
||||
|
||||
For the versions available, see the [tags on this
|
||||
repository](https://gitlab.freedesktop.org/slirp/libslirp/releases).
|
||||
|
||||
## License
|
||||
|
||||
See the [COPYRIGHT](COPYRIGHT) file for details.
|
BIN
src/net/libslirp/fuzzing/IN_arp/arp.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_arp/arp.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_dhcp/dhcp.pkt
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_dhcp/dhcp.pkt
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_dhcp/dhcp_capture.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_dhcp/dhcp_capture.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_icmp/icmp_capture.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_icmp/icmp_capture.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_icmp/ping_10-0-2-2.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_icmp/ping_10-0-2-2.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_icmp6/icmp_capture.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_icmp6/icmp_capture.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_icmp6/ndp.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_icmp6/ndp.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_ndp/ndp.pcap
|
BIN
src/net/libslirp/fuzzing/IN_icmp6/ping_10-0-2-2.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_icmp6/ping_10-0-2-2.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_ip-header/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_udp/DNS_freedesktop_1-1-1-1.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/dhcp.pkt
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/dhcp.pkt
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_dhcp/dhcp.pkt
|
1
src/net/libslirp/fuzzing/IN_ip-header/dhcp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/dhcp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_dhcp/dhcp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/icmp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/icmp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_icmp/icmp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/nc-10.0.2.2-8080.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/nc-10.0.2.2-8080.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tcp/nc-10.0.2.2-8080.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/nc-ident.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/nc-ident.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tcp/nc-ident.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/ping_10-0-2-2.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/ping_10-0-2-2.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_icmp/ping_10-0-2-2.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/tcp_qemucapt.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/tcp_qemucapt.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tcp/tcp_qemucapt.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/tftp-get-blah.pkt
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/tftp-get-blah.pkt
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp/tftp-get-blah.pkt
|
1
src/net/libslirp/fuzzing/IN_ip-header/tftp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/tftp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp/tftp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_ip-header/tftp_get_libslirp-txt.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip-header/tftp_get_libslirp-txt.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp/tftp_get_libslirp-txt.pcap
|
1
src/net/libslirp/fuzzing/IN_ip6-header/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip6-header/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_udp6/DNS_freedesktop_1-1-1-1.pcap
|
1
src/net/libslirp/fuzzing/IN_ip6-header/icmp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip6-header/icmp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_icmp6/icmp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_ip6-header/ping_10-0-2-2.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip6-header/ping_10-0-2-2.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_icmp6/ping_10-0-2-2.pcap
|
1
src/net/libslirp/fuzzing/IN_ip6-header/tcp_qemucapt.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip6-header/tcp_qemucapt.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tcp6/tcp_qemucapt.pcap
|
1
src/net/libslirp/fuzzing/IN_ip6-header/tftp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip6-header/tftp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_udp6/tftp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_ip6-header/tftp_get_libslirp-txt.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_ip6-header/tftp_get_libslirp-txt.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_udp6/tftp_get_libslirp-txt.pcap
|
BIN
src/net/libslirp/fuzzing/IN_ndp/ndp.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_ndp/ndp.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_tcp-d
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_tcp-d
vendored
Normal file
@ -0,0 +1 @@
|
||||
IN_tcp
|
1
src/net/libslirp/fuzzing/IN_tcp-h
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_tcp-h
vendored
Normal file
@ -0,0 +1 @@
|
||||
IN_tcp
|
BIN
src/net/libslirp/fuzzing/IN_tcp/nc-10.0.2.2-8080.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tcp/nc-10.0.2.2-8080.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tcp/nc-ident.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tcp/nc-ident.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tcp/tcp_qemucapt.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tcp/tcp_qemucapt.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_tcp6-d
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_tcp6-d
vendored
Normal file
@ -0,0 +1 @@
|
||||
IN_tcp6
|
1
src/net/libslirp/fuzzing/IN_tcp6-h
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_tcp6-h
vendored
Normal file
@ -0,0 +1 @@
|
||||
IN_tcp6
|
BIN
src/net/libslirp/fuzzing/IN_tcp6/tcp_qemucapt.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tcp6/tcp_qemucapt.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tftp/tftp-get-blah.pkt
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tftp/tftp-get-blah.pkt
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tftp/tftp_capture.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tftp/tftp_capture.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tftp/tftp_get_libslirp-txt.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tftp/tftp_get_libslirp-txt.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tftp6/tftp_capture.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tftp6/tftp_capture.pcap
vendored
Normal file
Binary file not shown.
BIN
src/net/libslirp/fuzzing/IN_tftp6/tftp_get_libslirp-txt.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_tftp6/tftp_get_libslirp-txt.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_udp-h
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp-h
vendored
Normal file
@ -0,0 +1 @@
|
||||
IN_udp
|
BIN
src/net/libslirp/fuzzing/IN_udp/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_udp/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_udp/dhcp.pkt
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp/dhcp.pkt
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_dhcp/dhcp.pkt
|
1
src/net/libslirp/fuzzing/IN_udp/dhcp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp/dhcp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_dhcp/dhcp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_udp/tftp-get-blah.pkt
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp/tftp-get-blah.pkt
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp/tftp-get-blah.pkt
|
1
src/net/libslirp/fuzzing/IN_udp/tftp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp/tftp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp/tftp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_udp/tftp_get_libslirp-txt.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp/tftp_get_libslirp-txt.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp/tftp_get_libslirp-txt.pcap
|
1
src/net/libslirp/fuzzing/IN_udp6-h
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp6-h
vendored
Normal file
@ -0,0 +1 @@
|
||||
IN_udp6
|
BIN
src/net/libslirp/fuzzing/IN_udp6/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
BIN
src/net/libslirp/fuzzing/IN_udp6/DNS_freedesktop_1-1-1-1.pcap
vendored
Normal file
Binary file not shown.
1
src/net/libslirp/fuzzing/IN_udp6/tftp_capture.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp6/tftp_capture.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp6/tftp_capture.pcap
|
1
src/net/libslirp/fuzzing/IN_udp6/tftp_get_libslirp-txt.pcap
vendored
Normal file
1
src/net/libslirp/fuzzing/IN_udp6/tftp_get_libslirp-txt.pcap
vendored
Normal file
@ -0,0 +1 @@
|
||||
../IN_tftp6/tftp_get_libslirp-txt.pcap
|
59
src/net/libslirp/fuzzing/README.md
vendored
Normal file
59
src/net/libslirp/fuzzing/README.md
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
# Fuzzing libslirp state and instructions
|
||||
|
||||
## Current state
|
||||
We chose to use libFuzzer because of its custom mutator feature, which allows to keep coherent informations inside the packets being sent to libslirp. This ease the process of fuzzing as packets are less likely to be rejected early during processing them.
|
||||
|
||||
In the current state, the `meson.build` file is not compatible with the original one used by libSlirp main repository but it should be easy to merge them in a clean way. Also **in the current state, it seems that there is a memory leak inside the fuzzing code**, which make it run out of memory. The current goal is to find and get rid of this leak to allow fuzzing for longer without the process being interrupted because of it.
|
||||
|
||||
Six harness are currently available, more are to be added later to focus on other parts of the code :
|
||||
|
||||
- **fuzz-ip-header** : the mutator focuses on the ip header field informations,
|
||||
- **fuzz-udp** : the mutator only work on udp packets, mutating the udp header and content, or only one or the other (-h,-d),
|
||||
- **fuzz-tcp** : the mutator targets tcp packets, header+data or only one or the other, or only one or the other (-h,-d),
|
||||
- **fuzz-icmp** : the mutator focuses on icmp packets,
|
||||
|
||||
These harness should be good starting examples on how to fuzz libslirp using libFuzzer.
|
||||
|
||||
## Running the fuzzer
|
||||
|
||||
Building the fuzzers/harness requires the use of clang as libFuzzer is part of LLVM.
|
||||
You can build it running :
|
||||
|
||||
`CC=clang meson build && ninja -C build`
|
||||
|
||||
It will build the fuzzer in the ./build/fuzzing/ directory.
|
||||
|
||||
A script named `fuzzing/coverage.py` is available to generate coverage informations. **It makes a lot of assumptions on the directory structure** and should be read before use.
|
||||
|
||||
To run the fuzzer, simply run some of:
|
||||
|
||||
- `build/fuzzing/fuzz-ip-header fuzzing/IN_ip-header`
|
||||
- `build/fuzzing/fuzz-udp fuzzing/IN_udp`
|
||||
- `build/fuzzing/fuzz-udp-h fuzzing/IN_udp-h`
|
||||
- `build/fuzzing/fuzz-tftp fuzzing/IN_tftp`
|
||||
- `build/fuzzing/fuzz-dhcp fuzzing/IN_dhcp`
|
||||
- `build/fuzzing/fuzz-icmp fuzzing/IN_icmp`
|
||||
- `build/fuzzing/fuzz-tcp fuzzing/IN_tcp`
|
||||
|
||||
Your current directory should be a separate directory as crashes to it. New inputs found by the fuzzer will go directly in the `IN` folder.
|
||||
|
||||
# Adding new files to the corpus
|
||||
|
||||
In its current state, the fuzzing code is taking pcap files as input, we produced some using `tcpdump` on linux inside qemu with default settings.
|
||||
Those files should be captured using the `EN10MB (Ethernet)` data link type, this can be set with the flag `-y` but it seems this can't be done while listening on all interfaces (`-i any`).
|
||||
New files should give new coverage, to ensure a new file is usefull the `coverage.py` script (see next section) can be used to compare the coverage with and without that new file.
|
||||
|
||||
# Coverage
|
||||
|
||||
The `coverage.py` script allows to see coverage informations about the corpus. It makes a lot of assumptions on the directory structure so it should be read and probably modified before running it.
|
||||
It must be called with the protocol to cover: `python coverage.py udp report`.
|
||||
To generate coverage informations, the following flags are passed to the fuzzer and libslirp :
|
||||
|
||||
- g
|
||||
- fsanitize-coverage=edge,indirect-calls,trace-cmp
|
||||
- fprofile-instr-generate
|
||||
- fcoverage-mapping
|
||||
|
||||
The last 2 arguments should also be passed to the linker.
|
||||
|
||||
Then the `llvm-profdata` and `llvm-cov` tools can be used to generate a report and a fancy set of HTML files with line-coverage informations.
|
37
src/net/libslirp/fuzzing/coverage.py
vendored
Normal file
37
src/net/libslirp/fuzzing/coverage.py
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
from os import chdir,listdir,environ
|
||||
from os.path import isfile,join,isdir
|
||||
from subprocess import DEVNULL, run
|
||||
import sys
|
||||
|
||||
ignored_files = "-ignore-filename-regex=glib -ignore-filename-regex=fuzz -ignore-filename-regex=helper -ignore-filename-regex=h$"
|
||||
|
||||
if __name__ == "__main__":
|
||||
chdir("build/fuzzing/out")
|
||||
available_targets = [exe for exe in listdir("../") if isfile(join("..", exe))]
|
||||
available_corpus_path = [exe for exe in listdir("../../../fuzzing/") if isdir(join("../../../fuzzing/", exe))]
|
||||
available_result_types = ["export", "show", "report"]
|
||||
if len(sys.argv) != 4 or sys.argv[1] not in available_targets or sys.argv[2] not in available_corpus_path or sys.argv[3] not in available_result_types:
|
||||
print("usage : python coverage.py fuzz_target IN_protol result_type")
|
||||
print(" - available targets : ")
|
||||
print(available_targets)
|
||||
print(" - available_corpus_path : ")
|
||||
print(available_corpus_path)
|
||||
print(" - available result types : ")
|
||||
print(available_result_types)
|
||||
exit(0)
|
||||
fuzzing_target = sys.argv[1]
|
||||
corpus_path = "../../../fuzzing/"+sys.argv[2]+"/"
|
||||
result_type = sys.argv[3]
|
||||
if fuzzing_target in available_targets:
|
||||
environ["LLVM_PROFILE_FILE"] = fuzzing_target + "_%p.profraw"
|
||||
corpus = listdir(corpus_path)
|
||||
for f in corpus:
|
||||
#print(corpus_path+f)
|
||||
run(["../" + fuzzing_target, corpus_path+f,"-detect_leaks=0"], stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL)
|
||||
run(["llvm-profdata merge -sparse " + fuzzing_target + "_*.profraw -o " + fuzzing_target + ".profdata"], shell=True)
|
||||
if result_type == "export" :
|
||||
run(["llvm-cov show ../" + fuzzing_target + " -format=html -output-dir=../report -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
|
||||
elif result_type == "show" :
|
||||
run(["llvm-cov show ../" + fuzzing_target + " -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
|
||||
else:
|
||||
run(["llvm-cov report ../" + fuzzing_target + " -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
|
2
src/net/libslirp/fuzzing/fuzz-input.options
vendored
Normal file
2
src/net/libslirp/fuzzing/fuzz-input.options
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 1024
|
35
src/net/libslirp/fuzzing/fuzz-main.c
vendored
Normal file
35
src/net/libslirp/fuzzing/fuzz-main.c
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MIN_NUMBER_OF_RUNS 1
|
||||
#define EXIT_TEST_SKIP 77
|
||||
|
||||
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
GError *err = NULL;
|
||||
char *name = argv[i];
|
||||
char *buf;
|
||||
size_t size;
|
||||
|
||||
if (!g_file_get_contents(name, &buf, &size, &err)) {
|
||||
g_warning("Failed to read '%s': %s", name, err->message);
|
||||
g_clear_error(&err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
g_print("%s...\n", name);
|
||||
for (j = 0; j < MIN_NUMBER_OF_RUNS; j++) {
|
||||
if (LLVMFuzzerTestOneInput((void *)buf, size) == EXIT_TEST_SKIP) {
|
||||
return EXIT_TEST_SKIP;
|
||||
}
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
271
src/net/libslirp/fuzzing/helper.c
vendored
Normal file
271
src/net/libslirp/fuzzing/helper.c
vendored
Normal file
@ -0,0 +1,271 @@
|
||||
#include "helper.h"
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#define MIN_NUMBER_OF_RUNS 1
|
||||
#define EXIT_TEST_SKIP 77
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
struct in6_addr ip6_host;
|
||||
struct in6_addr ip6_dns;
|
||||
|
||||
/// Function to compute the checksum of the ip header, should be compatible with
|
||||
/// TCP and UDP checksum calculation too.
|
||||
uint16_t compute_checksum(uint8_t *Data, size_t Size)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
uint16_t *Data_as_u16 = (uint16_t *)Data;
|
||||
|
||||
for (size_t i = 0; i < Size / 2; i++) {
|
||||
uint16_t val = ntohs(*(Data_as_u16 + i));
|
||||
sum += val;
|
||||
}
|
||||
if (Size % 2 == 1)
|
||||
sum += Data[Size - 1] << 8;
|
||||
|
||||
uint16_t carry = sum >> 16;
|
||||
uint32_t sum_val = carry + (sum & 0xFFFF);
|
||||
uint16_t result = (sum_val >> 16) + (sum_val & 0xFFFF);
|
||||
return ~result;
|
||||
}
|
||||
|
||||
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
/* FIXME: fail on some addr? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int listen(int sockfd, int backlog)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
/* FIXME: fail on some addr? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
/* FIXME: partial send? */
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
/* FIXME: partial send? */
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
|
||||
{
|
||||
memset(buf, 0, len);
|
||||
return len / 2;
|
||||
}
|
||||
|
||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen)
|
||||
{
|
||||
memset(buf, 0, len);
|
||||
memset(src_addr, 0, *addrlen);
|
||||
return len / 2;
|
||||
}
|
||||
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
static void empty_logging_func(const gchar *log_domain,
|
||||
GLogLevelFlags log_level, const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disables logging for oss-fuzz. Must be used with each target. */
|
||||
static void fuzz_set_logging_func(void)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
g_log_set_default_handler(empty_logging_func, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t send_packet(const void *pkt, size_t pkt_len, void *opaque)
|
||||
{
|
||||
return pkt_len;
|
||||
}
|
||||
|
||||
static int64_t clock_get_ns(void *opaque)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void timer_mod(void *timer, int64_t expire_timer, void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static void timer_free(void *timer, void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static void guest_error(const char *msg, void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static void register_poll_fd(int fd, void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static void unregister_poll_fd(int fd, void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static void notify(void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static const SlirpCb slirp_cb = {
|
||||
.send_packet = send_packet,
|
||||
.guest_error = guest_error,
|
||||
.clock_get_ns = clock_get_ns,
|
||||
.timer_new = timer_new,
|
||||
.timer_mod = timer_mod,
|
||||
.timer_free = timer_free,
|
||||
.register_poll_fd = register_poll_fd,
|
||||
.unregister_poll_fd = unregister_poll_fd,
|
||||
.notify = notify,
|
||||
};
|
||||
|
||||
#define MAX_EVID 1024
|
||||
static int fake_events[MAX_EVID];
|
||||
|
||||
static int add_poll_cb(int fd, int events, void *opaque)
|
||||
{
|
||||
g_assert(fd < G_N_ELEMENTS(fake_events));
|
||||
fake_events[fd] = events;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int get_revents_cb(int idx, void *opaque)
|
||||
{
|
||||
return fake_events[idx] & ~(SLIRP_POLL_ERR | SLIRP_POLL_HUP);
|
||||
}
|
||||
|
||||
// Fuzzing strategy is the following :
|
||||
// LLVMFuzzerTestOneInput :
|
||||
// - build a slirp instance,
|
||||
// - extract the packets from the pcap one by one,
|
||||
// - send the data to `slirp_input`
|
||||
// - call `slirp_pollfds_fill` and `slirp_pollfds_poll` to advance slirp
|
||||
// - cleanup slirp when the whole pcap has been unwrapped.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
Slirp *slirp = NULL;
|
||||
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
|
||||
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
|
||||
struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
|
||||
struct in_addr fwd = { .s_addr = htonl(0x0a000205) }; /* 10.0.2.5 */
|
||||
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
|
||||
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
|
||||
struct in6_addr ip6_prefix;
|
||||
int ret, vprefix6_len = 64;
|
||||
const char *vhostname = NULL;
|
||||
const char *tftp_server_name = NULL;
|
||||
const char *tftp_export = "fuzzing/tftp";
|
||||
const char *bootfile = NULL;
|
||||
const char **dnssearch = NULL;
|
||||
const char *vdomainname = NULL;
|
||||
const pcap_hdr_t *hdr = (const void *)data;
|
||||
const pcaprec_hdr_t *rec = NULL;
|
||||
uint32_t timeout = 0;
|
||||
|
||||
if (size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
data += sizeof(*hdr);
|
||||
size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setenv("SLIRP_FUZZING", "1", 0);
|
||||
|
||||
fuzz_set_logging_func();
|
||||
|
||||
ret = inet_pton(AF_INET6, "fec0::", &ip6_prefix);
|
||||
g_assert_cmpint(ret, ==, 1);
|
||||
|
||||
ip6_host = ip6_prefix;
|
||||
ip6_host.s6_addr[15] |= 2;
|
||||
ip6_dns = ip6_prefix;
|
||||
ip6_dns.s6_addr[15] |= 3;
|
||||
|
||||
slirp =
|
||||
slirp_init(false, true, net, mask, host, true, ip6_prefix, vprefix6_len,
|
||||
ip6_host, vhostname, tftp_server_name, tftp_export, bootfile,
|
||||
dhcp, dns, ip6_dns, dnssearch, vdomainname, &slirp_cb, NULL);
|
||||
|
||||
slirp_add_exec(slirp, "cat", &fwd, 1234);
|
||||
|
||||
|
||||
for ( ; size > sizeof(*rec); data += rec->incl_len, size -= rec->incl_len) {
|
||||
rec = (const void *)data;
|
||||
data += sizeof(*rec);
|
||||
size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
g_debug("unsupported rec->incl_len != rec->orig_len");
|
||||
break;
|
||||
}
|
||||
if (rec->incl_len > size) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rec->incl_len >= 14) {
|
||||
if (data[12] == 0x08 && data[13] == 0x00) {
|
||||
/* IPv4 */
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
uint32_t ipsource = * (uint32_t*) (data + 14 + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
} else if (data[12] == 0x86 && data[13] == 0xdd) {
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (data + 14 + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slirp_input(slirp, data, rec->incl_len);
|
||||
slirp_pollfds_fill(slirp, &timeout, add_poll_cb, NULL);
|
||||
slirp_pollfds_poll(slirp, 0, get_revents_cb, NULL);
|
||||
}
|
||||
|
||||
slirp_cleanup(slirp);
|
||||
|
||||
return 0;
|
||||
}
|
24
src/net/libslirp/fuzzing/helper.h
vendored
Normal file
24
src/net/libslirp/fuzzing/helper.h
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef _HELPER_H
|
||||
#define _HELPER_H
|
||||
|
||||
#ifdef _WIN32
|
||||
/* as defined in sdkddkver.h */
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 /* Vista */
|
||||
#endif
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define PSEUDO_IP_SIZE (4*2 + 4)
|
||||
#define PSEUDO_IPV6_SIZE (16*2 + 4)
|
||||
|
||||
uint16_t compute_checksum(uint8_t *Data, size_t Size);
|
||||
|
||||
extern struct in6_addr ip6_host;
|
||||
extern struct in6_addr ip6_dns;
|
||||
|
||||
#endif /* _HELPER_H */
|
64
src/net/libslirp/fuzzing/meson.build
vendored
Normal file
64
src/net/libslirp/fuzzing/meson.build
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
extra_sources = []
|
||||
extra_cargs = []
|
||||
extra_ldargs = []
|
||||
fuzzing_engine = []
|
||||
|
||||
|
||||
extra_cargs += '-g'
|
||||
if fuzzer_build
|
||||
extra_cargs += '-fsanitize=fuzzer,address'
|
||||
extra_cargs += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
|
||||
extra_cargs += '-DCUSTOM_MUTATOR'
|
||||
extra_cargs += '-fprofile-instr-generate'
|
||||
extra_cargs += '-fcoverage-mapping'
|
||||
|
||||
extra_ldargs += '-fsanitize=fuzzer,address'
|
||||
extra_ldargs += '-fprofile-instr-generate'
|
||||
extra_ldargs += '-fcoverage-mapping'
|
||||
endif
|
||||
|
||||
deps = [glib_dep, libslirp_dep, platform_deps]
|
||||
|
||||
exes = [
|
||||
['fuzz-arp', ['slirp_fuzz_arp.c', 'helper.c']],
|
||||
['fuzz-ip-header', ['slirp_fuzz_ip_header.c', 'helper.c']],
|
||||
['fuzz-udp', ['slirp_fuzz_udp.c', 'helper.c']],
|
||||
['fuzz-udp-h', ['slirp_fuzz_udp_header.c', 'helper.c']],
|
||||
['fuzz-udp-d', ['slirp_fuzz_udp_data.c', 'helper.c']],
|
||||
['fuzz-tftp', ['slirp_fuzz_udp_data.c', 'helper.c']],
|
||||
['fuzz-dhcp', ['slirp_fuzz_udp_data.c', 'helper.c']],
|
||||
['fuzz-tcp', ['slirp_fuzz_tcp.c', 'helper.c']],
|
||||
['fuzz-tcp-h', ['slirp_fuzz_tcp_header.c', 'helper.c']],
|
||||
['fuzz-tcp-d', ['slirp_fuzz_tcp_data.c', 'helper.c']],
|
||||
['fuzz-icmp', ['slirp_fuzz_icmp.c', 'helper.c']],
|
||||
|
||||
['fuzz-ndp', ['slirp_fuzz_icmp6.c', 'helper.c']],
|
||||
['fuzz-ip6-header', ['slirp_fuzz_ip6_header.c', 'helper.c']],
|
||||
['fuzz-udp6', ['slirp_fuzz_udp6.c', 'helper.c']],
|
||||
['fuzz-udp6-h', ['slirp_fuzz_udp6_header.c', 'helper.c']],
|
||||
['fuzz-udp6-d', ['slirp_fuzz_udp6_data.c', 'helper.c']],
|
||||
['fuzz-tftp6', ['slirp_fuzz_udp6_data.c', 'helper.c']],
|
||||
['fuzz-tcp6', ['slirp_fuzz_tcp6.c', 'helper.c']],
|
||||
['fuzz-tcp6-h', ['slirp_fuzz_tcp6_header.c', 'helper.c']],
|
||||
['fuzz-tcp6-d', ['slirp_fuzz_tcp6_data.c', 'helper.c']],
|
||||
['fuzz-icmp6', ['slirp_fuzz_icmp6.c', 'helper.c']],
|
||||
]
|
||||
|
||||
if fuzzer_build
|
||||
foreach exe : exes
|
||||
executable(
|
||||
exe[0], exe[1],
|
||||
dependencies : deps,
|
||||
c_args: extra_cargs,
|
||||
link_args: extra_ldargs,
|
||||
)
|
||||
endforeach
|
||||
endif
|
||||
|
||||
if fuzz_reproduce
|
||||
executable(['reproducer', ['reproducer.c', 'helper.c']],
|
||||
dependencies: deps,
|
||||
c_args: extra_cargs,
|
||||
link_args: extra_ldargs,
|
||||
)
|
||||
endif
|
48
src/net/libslirp/fuzzing/oss-fuzz.sh
vendored
Normal file
48
src/net/libslirp/fuzzing/oss-fuzz.sh
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
export CC=${CC:-clang}
|
||||
export CXX=${CXX:-clang++}
|
||||
export WORK=${WORK:-$(pwd)}
|
||||
export OUT=${OUT:-$(pwd)/out}
|
||||
|
||||
build=$WORK/build
|
||||
rm -rf $build
|
||||
mkdir -p $build
|
||||
mkdir -p $OUT
|
||||
|
||||
fuzzflag="oss-fuzz=true"
|
||||
if [ -z "$FUZZING_ENGINE" ]; then
|
||||
fuzzflag="llvm-fuzz=true"
|
||||
fi
|
||||
|
||||
meson $build \
|
||||
-D$fuzzflag \
|
||||
-Db_lundef=false \
|
||||
-Ddefault_library=static \
|
||||
-Dstatic=true \
|
||||
-Dbuildtype=debugoptimized
|
||||
|
||||
ninja -C $build
|
||||
|
||||
zip -jqr $OUT/fuzz-arp_seed_corpus.zip "$(dirname "$0")/IN_arp"
|
||||
zip -jqr $OUT/fuzz-ip-header_seed_corpus.zip "$(dirname "$0")/IN_ip-header"
|
||||
zip -jqr $OUT/fuzz-udp_seed_corpus.zip "$(dirname "$0")/IN_udp"
|
||||
zip -jqr $OUT/fuzz-udp-h_seed_corpus.zip "$(dirname "$0")/IN_udp-h"
|
||||
zip -jqr $OUT/fuzz-tftp_seed_corpus.zip "$(dirname "$0")/IN_tftp"
|
||||
zip -jqr $OUT/fuzz-dhcp_seed_corpus.zip "$(dirname "$0")/IN_dhcp"
|
||||
zip -jqr $OUT/fuzz-icmp_seed_corpus.zip "$(dirname "$0")/IN_icmp"
|
||||
zip -jqr $OUT/fuzz-tcp_seed_corpus.zip "$(dirname "$0")/IN_tcp"
|
||||
zip -jqr $OUT/fuzz-tcp-h_seed_corpus.zip "$(dirname "$0")/IN_tcp-h"
|
||||
|
||||
zip -jqr $OUT/fuzz-ndp_seed_corpus.zip "$(dirname "$0")/IN_ndp"
|
||||
zip -jqr $OUT/fuzz-ip6-header_seed_corpus.zip "$(dirname "$0")/IN_ip6-header"
|
||||
zip -jqr $OUT/fuzz-udp6_seed_corpus.zip "$(dirname "$0")/IN_udp6"
|
||||
zip -jqr $OUT/fuzz-udp6-h_seed_corpus.zip "$(dirname "$0")/IN_udp6-h"
|
||||
zip -jqr $OUT/fuzz-tftp6_seed_corpus.zip "$(dirname "$0")/IN_tftp6"
|
||||
zip -jqr $OUT/fuzz-icmp6_seed_corpus.zip "$(dirname "$0")/IN_icmp6"
|
||||
zip -jqr $OUT/fuzz-tcp6_seed_corpus.zip "$(dirname "$0")/IN_tcp6"
|
||||
|
||||
find $build -type f -executable -name "fuzz-*" -exec mv {} $OUT \;
|
||||
find $build -type f -name "*.options" -exec mv {} $OUT \;
|
45
src/net/libslirp/fuzzing/reproducer.c
vendored
Normal file
45
src/net/libslirp/fuzzing/reproducer.c
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
#ifdef _WIN32
|
||||
/* as defined in sdkddkver.h */
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 /* Vista */
|
||||
#endif
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
|
||||
#define MIN_NUMBER_OF_RUNS 1
|
||||
#define EXIT_TEST_SKIP 77
|
||||
|
||||
extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
GError *err = NULL;
|
||||
char *name = argv[i];
|
||||
char *buf;
|
||||
size_t size;
|
||||
|
||||
if (!g_file_get_contents(name, &buf, &size, &err)) {
|
||||
g_warning("Failed to read '%s': %s", name, err->message);
|
||||
g_clear_error(&err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
g_print("%s...\n", name);
|
||||
for (j = 0; j < MIN_NUMBER_OF_RUNS; j++) {
|
||||
if (LLVMFuzzerTestOneInput((void *)buf, size) == EXIT_TEST_SKIP) {
|
||||
return EXIT_TEST_SKIP;
|
||||
}
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
23
src/net/libslirp/fuzzing/slirp_base_fuzz.h
vendored
Normal file
23
src/net/libslirp/fuzzing/slirp_base_fuzz.h
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
|
||||
/* Structure for the fuzzers */
|
||||
typedef struct pcap_hdr_s {
|
||||
guint32 magic_number; /* magic number */
|
||||
guint16 version_major; /* major version number */
|
||||
guint16 version_minor; /* minor version number */
|
||||
gint32 thiszone; /* GMT to local correction */
|
||||
guint32 sigfigs; /* accuracy of timestamps */
|
||||
guint32 snaplen; /* max length of captured packets, in octets */
|
||||
guint32 network; /* data link type */
|
||||
} pcap_hdr_t;
|
||||
|
||||
typedef struct pcaprec_hdr_s {
|
||||
guint32 ts_sec; /* timestamp seconds */
|
||||
guint32 ts_usec; /* timestamp microseconds */
|
||||
guint32 incl_len; /* number of octets of packet saved in file */
|
||||
guint32 orig_len; /* actual length of packet */
|
||||
} pcaprec_hdr_t;
|
90
src/net/libslirp/fuzzing/slirp_fuzz_arp.c
vendored
Normal file
90
src/net/libslirp/fuzzing/slirp_fuzz_arp.c
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *arp_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
arp_data = Data_ptr + 14;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint16_t arp_size = rec->incl_len - 14;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the ip header, maybe the IPs or
|
||||
// total length should be excluded ?
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, arp_data, arp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// For now we dont want to change the header size as it would require to
|
||||
// resize the `Data` array to include the new bytes inside the whole
|
||||
// packet.
|
||||
// This should be easy as LibFuzzer probably does it by itself or
|
||||
// reserved enough space in Data beforehand, needs some research to
|
||||
// confirm.
|
||||
// FIXME: allow up to grow header size to 60 bytes,
|
||||
// requires to update the `header length` before calculating
|
||||
// checksum
|
||||
LLVMFuzzerMutate(Data_to_mutate, arp_size, arp_size);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(arp_data, Data_to_mutate, arp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
129
src/net/libslirp/fuzzing/slirp_fuzz_icmp.c
vendored
Normal file
129
src/net/libslirp/fuzzing/slirp_fuzz_icmp.c
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not ICMP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_ICMP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
|
||||
uint16_t total_length =
|
||||
ntohs(*((uint16_t *)ip_data + 1)); // network order to host order
|
||||
uint16_t icmp_size =
|
||||
(total_length - ip_hl_in_bytes); /* total length -> is stored at the
|
||||
offset 2 in the header */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in icmp
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// For now we dont want to change the header size as it would require to
|
||||
// resize the `Data` array to include the new bytes inside the whole
|
||||
// packet.
|
||||
// This should be easy as LibFuzzer probably does it by itself or
|
||||
// reserved enough space in Data beforehand, needs some research to
|
||||
// confirm.
|
||||
// FIXME: allow up to grow header size to 60 bytes,
|
||||
// requires to update the `header length` before calculating
|
||||
// checksum
|
||||
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
|
||||
|
||||
// Set the `checksum` field to 0 and calculate the new checksum
|
||||
*(uint16_t *)(Data_to_mutate + 2) = 0;
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, icmp_size);
|
||||
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
134
src/net/libslirp/fuzzing/slirp_fuzz_icmp6.c
vendored
Normal file
134
src/net/libslirp/fuzzing/slirp_fuzz_icmp6.c
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not ICMP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_ICMPV6)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
|
||||
uint16_t icmp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in icmp
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// For now we dont want to change the header size as it would require to
|
||||
// resize the `Data` array to include the new bytes inside the whole
|
||||
// packet.
|
||||
// This should be easy as LibFuzzer probably does it by itself or
|
||||
// reserved enough space in Data beforehand, needs some research to
|
||||
// confirm.
|
||||
// FIXME: allow up to grow header size to 60 bytes,
|
||||
// requires to update the `header length` before calculating
|
||||
// checksum
|
||||
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
|
||||
|
||||
// Set the `checksum` field to 0 and calculate the new checksum
|
||||
*(uint16_t *)(Data_to_mutate + 2) = 0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + icmp_size, ip_data + 8, 16*2);
|
||||
|
||||
*(Data_to_mutate + icmp_size + 16*2 + 1) = IPPROTO_ICMPV6;
|
||||
|
||||
*(Data_to_mutate + icmp_size + 16*2 + 2) = (uint8_t)(icmp_size / 256);
|
||||
*(Data_to_mutate + icmp_size + 16*2 + 3) = (uint8_t)(icmp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, icmp_size + PSEUDO_IPV6_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
103
src/net/libslirp/fuzzing/slirp_fuzz_ip6_header.c
vendored
Normal file
103
src/net/libslirp/fuzzing/slirp_fuzz_ip6_header.c
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the ip header, maybe the IPs or
|
||||
// total length should be excluded ?
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, ip_data, ip_hl_in_bytes);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// For now we dont want to change the header size as it would require to
|
||||
// resize the `Data` array to include the new bytes inside the whole
|
||||
// packet.
|
||||
// This should be easy as LibFuzzer probably does it by itself or
|
||||
// reserved enough space in Data beforehand, needs some research to
|
||||
// confirm.
|
||||
// FIXME: allow up to grow header size to 60 bytes,
|
||||
// requires to update the `header length` before calculating
|
||||
// checksum
|
||||
LLVMFuzzerMutate(Data_to_mutate, ip_hl_in_bytes, ip_hl_in_bytes);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(ip_data, Data_to_mutate, ip_hl_in_bytes);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
112
src/net/libslirp/fuzzing/slirp_fuzz_ip_header.c
vendored
Normal file
112
src/net/libslirp/fuzzing/slirp_fuzz_ip_header.c
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > MaxSize || ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the ip header, maybe the IPs or
|
||||
// total length should be excluded ?
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, ip_data, ip_hl_in_bytes);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// For now we dont want to change the header size as it would require to
|
||||
// resize the `Data` array to include the new bytes inside the whole
|
||||
// packet.
|
||||
// This should be easy as LibFuzzer probably does it by itself or
|
||||
// reserved enough space in Data beforehand, needs some research to
|
||||
// confirm.
|
||||
// FIXME: allow up to grow header size to 60 bytes,
|
||||
// requires to update the `header length` before calculating
|
||||
// checksum
|
||||
LLVMFuzzerMutate(Data_to_mutate, ip_hl_in_bytes, ip_hl_in_bytes);
|
||||
|
||||
// Set the `checksum` field to 0 and calculate the new checksum
|
||||
*(uint16_t *)(Data_to_mutate + 10) = 0;
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, ip_hl_in_bytes);
|
||||
*(uint16_t *)(Data_to_mutate + 10) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(ip_data, Data_to_mutate, ip_hl_in_bytes);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
138
src/net/libslirp/fuzzing/slirp_fuzz_tcp.c
vendored
Normal file
138
src/net/libslirp/fuzzing/slirp_fuzz_tcp.c
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, tcp_size, tcp_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
134
src/net/libslirp/fuzzing/slirp_fuzz_tcp6.c
vendored
Normal file
134
src/net/libslirp/fuzzing/slirp_fuzz_tcp6.c
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, tcp_size, tcp_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
137
src/net/libslirp/fuzzing/slirp_fuzz_tcp6_data.c
vendored
Normal file
137
src/net/libslirp/fuzzing/slirp_fuzz_tcp6_data.c
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
|
||||
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
|
||||
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
136
src/net/libslirp/fuzzing/slirp_fuzz_tcp6_header.c
vendored
Normal file
136
src/net/libslirp/fuzzing/slirp_fuzz_tcp6_header.c
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t tcp_header_size = (*(start_of_tcp + 12) >> 4) * 4;
|
||||
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes ||
|
||||
tcp_header_size > MaxSize || tcp_header_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, tcp_header_size, tcp_header_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
141
src/net/libslirp/fuzzing/slirp_fuzz_tcp_data.c
vendored
Normal file
141
src/net/libslirp/fuzzing/slirp_fuzz_tcp_data.c
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
|
||||
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
|
||||
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
140
src/net/libslirp/fuzzing/slirp_fuzz_tcp_header.c
vendored
Normal file
140
src/net/libslirp/fuzzing/slirp_fuzz_tcp_header.c
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t tcp_header_size = (*(start_of_tcp + 12) >> 4) * 4;
|
||||
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes ||
|
||||
tcp_header_size > MaxSize || tcp_header_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, tcp_header_size, tcp_header_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||
// Copy the source and destination IP addresses, the tcp length and
|
||||
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||
// the new checksum.
|
||||
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
121
src/net/libslirp/fuzzing/slirp_fuzz_udp.c
vendored
Normal file
121
src/net/libslirp/fuzzing/slirp_fuzz_udp.c
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not UDP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_UDP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the udp packet
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the UDP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, udp_size, udp_size);
|
||||
|
||||
// Drop checksum
|
||||
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
120
src/net/libslirp/fuzzing/slirp_fuzz_udp6.c
vendored
Normal file
120
src/net/libslirp/fuzzing/slirp_fuzz_udp6.c
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not UDP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_UDP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the udp packet
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the UDP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, udp_size, udp_size);
|
||||
|
||||
// Drop checksum
|
||||
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
|
||||
// check that actually
|
||||
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
122
src/net/libslirp/fuzzing/slirp_fuzz_udp6_data.c
vendored
Normal file
122
src/net/libslirp/fuzzing/slirp_fuzz_udp6_data.c
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not UDP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_UDP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t udp_header_size = 8;
|
||||
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
uint16_t udp_data_size = (udp_size - (uint16_t)udp_header_size);
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (udp_data_size > MaxSize || udp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - udp_header_size)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the udp packet
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the UDP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate + udp_header_size, udp_data_size, udp_data_size);
|
||||
|
||||
// Drop checksum
|
||||
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
|
||||
// check that actually
|
||||
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
121
src/net/libslirp/fuzzing/slirp_fuzz_udp6_header.c
vendored
Normal file
121
src/net/libslirp/fuzzing/slirp_fuzz_udp6_header.c
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "../src/ip6.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 24) {
|
||||
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||
|
||||
// This an answer, which we will produce, so don't receive
|
||||
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not UDP from the mutation strategy
|
||||
if (ip_data[6] != IPPROTO_UDP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t udp_header_size = 8;
|
||||
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the udp packet
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the UDP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, udp_header_size, udp_header_size);
|
||||
|
||||
// Drop checksum
|
||||
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
|
||||
// check that actually
|
||||
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
123
src/net/libslirp/fuzzing/slirp_fuzz_udp_data.c
vendored
Normal file
123
src/net/libslirp/fuzzing/slirp_fuzz_udp_data.c
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not UDP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_UDP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t udp_header_size = 8;
|
||||
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
|
||||
uint16_t udp_data_size = (udp_size - (uint16_t)udp_header_size);
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (udp_data_size > MaxSize || udp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - udp_header_size)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the udp packet
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the UDP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate + udp_header_size, udp_data_size, udp_data_size);
|
||||
|
||||
// Drop checksum
|
||||
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
122
src/net/libslirp/fuzzing/slirp_fuzz_udp_header.c
vendored
Normal file
122
src/net/libslirp/fuzzing/slirp_fuzz_udp_header.c
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.h"
|
||||
#include "helper.h"
|
||||
#include "slirp_base_fuzz.h"
|
||||
|
||||
#ifdef CUSTOM_MUTATOR
|
||||
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||
|
||||
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize, unsigned int Seed)
|
||||
{
|
||||
size_t current_size = Size;
|
||||
uint8_t *Data_ptr = Data;
|
||||
uint8_t *ip_data;
|
||||
uint32_t ipsource;
|
||||
bool mutated = false;
|
||||
|
||||
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||
pcaprec_hdr_t *rec = NULL;
|
||||
|
||||
if (current_size < sizeof(pcap_hdr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data_ptr += sizeof(*hdr);
|
||||
current_size -= sizeof(*hdr);
|
||||
|
||||
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||
g_debug("FIXME: byteswap fields");
|
||||
return 0;
|
||||
} /* else assume native pcap file */
|
||||
if (hdr->network != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||
rec = (void *)Data_ptr;
|
||||
Data_ptr += sizeof(*rec);
|
||||
current_size -= sizeof(*rec);
|
||||
|
||||
if (rec->incl_len != rec->orig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len > current_size) {
|
||||
return 0;
|
||||
}
|
||||
if (rec->incl_len < 14 + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip_data = Data_ptr + 14;
|
||||
|
||||
if (rec->incl_len >= 14 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not UDP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_UDP)
|
||||
continue;
|
||||
|
||||
uint8_t Data_to_mutate[MaxSize];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||
return 0;
|
||||
|
||||
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t udp_header_size = 8;
|
||||
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
|
||||
|
||||
// The size inside the packet can't be trusted, if it is too big it can
|
||||
// lead to heap overflows in the fuzzing code.
|
||||
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the udp packet
|
||||
memset(Data_to_mutate, 0, MaxSize);
|
||||
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the UDP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate, udp_header_size, udp_header_size);
|
||||
|
||||
// Drop checksum
|
||||
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
BIN
src/net/libslirp/fuzzing/tftp/toto
vendored
Normal file
BIN
src/net/libslirp/fuzzing/tftp/toto
vendored
Normal file
Binary file not shown.
132
src/net/libslirp/glib/glib.c
vendored
Normal file
132
src/net/libslirp/glib/glib.c
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
//
|
||||
// Created by nhp on 14-05-24.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "glib.h"
|
||||
|
||||
GString* g_string_new(gchar* initial) {
|
||||
GString* str = g_new0(GString, 1);
|
||||
|
||||
if (initial != NULL) {
|
||||
int len = strlen(initial);
|
||||
gchar* p = malloc(len);
|
||||
memcpy(p, initial, len);
|
||||
str->str = p;
|
||||
str->len = len;
|
||||
str->allocated_len = len;
|
||||
} else {
|
||||
gchar* p = malloc(64);
|
||||
str->str = p;
|
||||
str->len = 0;
|
||||
str->allocated_len = 64;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
gchar* g_string_free(GString* str, gboolean free_segment) {
|
||||
char* seg = str->str;
|
||||
free(str);
|
||||
if (free_segment) {
|
||||
free(str->str);
|
||||
return NULL;
|
||||
}
|
||||
return seg;
|
||||
}
|
||||
|
||||
void g_string_append_printf(GString* str, const gchar* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int need_len = vsnprintf(NULL, 0, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (str->len + need_len + 1 < str->allocated_len) {
|
||||
gsize new_len = str->len + need_len + 1;
|
||||
gchar* newp = realloc(str->str, new_len);
|
||||
str->str = newp;
|
||||
str->allocated_len = new_len;
|
||||
str->len = new_len - 1;
|
||||
}
|
||||
|
||||
gchar* temp = malloc(need_len + 1);
|
||||
va_start(args, format);
|
||||
vsnprintf(temp, need_len, format, args);
|
||||
va_end(args);
|
||||
|
||||
strcat(str->str, temp);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
gchar* g_strstr_len(const gchar* haystack, int len, const gchar* needle) {
|
||||
if (len == -1) return strstr(haystack, needle);
|
||||
size_t needle_len = strlen(needle);
|
||||
for (int i = 0; i < len; i++) {
|
||||
size_t found = 0;
|
||||
for (int j = i; j < len; j++) {
|
||||
if (haystack[j] == needle[j - i]) found++;
|
||||
else break;
|
||||
if (found == needle_len) return (gchar*) haystack + j;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar* g_strdup(const gchar* str) {
|
||||
if (str == NULL) return NULL;
|
||||
else return strdup(str);
|
||||
}
|
||||
|
||||
int g_strv_length(GStrv strings) {
|
||||
gint count = 0;
|
||||
while (strings[count])
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
void g_strfreev(GStrv strings) {
|
||||
for (int i = 0; strings[i] != NULL; i++) {
|
||||
free(strings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// This is not good but all we're using slirp for is beaming pokemans over the internet so it's probably okay
|
||||
gint g_rand_int_range(GRand* grand, gint min, gint max) {
|
||||
double r = (double) rand();
|
||||
double range = (double) (max - min);
|
||||
double r2 = (r / (double) RAND_MAX) * range;
|
||||
return MIN(max, ((int) r2) + min);
|
||||
}
|
||||
|
||||
GRand* g_rand_new() {
|
||||
return malloc(sizeof(GRand));
|
||||
}
|
||||
|
||||
void g_rand_free(GRand* rand) {
|
||||
free(rand);
|
||||
}
|
||||
|
||||
void g_error_free(GError* error) {
|
||||
free(error);
|
||||
}
|
||||
|
||||
gboolean g_shell_parse_argv(const gchar* command_line, gint* argcp, gchar*** argvp, GError** error) {
|
||||
const gchar* message = "Unimplemented.";
|
||||
GError* err = malloc(sizeof(GError));
|
||||
err->message = message;
|
||||
*error = err;
|
||||
return false;
|
||||
}
|
||||
|
||||
gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
|
||||
gchar **envp, GSpawnFlags flags,
|
||||
GSpawnChildSetupFunc child_setup,
|
||||
gpointer user_data, GPid *child_pid, gint stdin_fd,
|
||||
gint stdout_fd, gint stderr_fd, GError **error)
|
||||
{
|
||||
return false;
|
||||
}
|
162
src/net/libslirp/glib/glib.h
vendored
Normal file
162
src/net/libslirp/glib/glib.h
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
#ifndef GLIB_SHIM_H
|
||||
#define GLIB_SHIM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(_MSC_VER)
|
||||
#define G_OS_WIN32 1
|
||||
#endif
|
||||
|
||||
#define G_LITTLE_ENDIAN 0
|
||||
#define G_BIG_ENDIAN 1
|
||||
#define G_BYTE_ORDER G_LITTLE_ENDIAN
|
||||
|
||||
#define GUINT16_FROM_BE(n) ntohs(n)
|
||||
#define GUINT16_TO_BE(n) htons(n)
|
||||
#define GUINT32_FROM_BE(n) ntohl(n)
|
||||
#define GUINT32_TO_BE(n) htonl(n)
|
||||
|
||||
#define GINT16_TO_BE(n) (int16_t) htons(n)
|
||||
#define GINT16_FROM_BE(n) (int16_t) ntohs(n)
|
||||
#define GINT32_TO_BE(n) (int32_t) htonl(n)
|
||||
#define GINT32_FROM_BE(n) (int32_t) ntohl(n)
|
||||
|
||||
#define G_N_ELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
#define G_GNUC_PRINTF(x, y)
|
||||
|
||||
#define GLIB_CHECK_VERSION(x, y, z) 1
|
||||
#define G_STATIC_ASSERT(...)
|
||||
#define g_assert assert
|
||||
#define G_UNLIKELY(x) __builtin_expect(x, 0)
|
||||
|
||||
#define g_return_if_fail(expr) \
|
||||
do { \
|
||||
if (!(expr)) \
|
||||
return; \
|
||||
} while (false)
|
||||
|
||||
#define g_return_val_if_fail(expr, val) \
|
||||
do { \
|
||||
if (!(expr)) \
|
||||
return (val); \
|
||||
} while (false)
|
||||
|
||||
#define g_warn_if_reached() \
|
||||
do { \
|
||||
g_warning("g_warn_if_reached: Reached " __FILE__ ":%d", __LINE__); \
|
||||
} while (false)
|
||||
|
||||
|
||||
#define g_warn_if_fail(expr) \
|
||||
do { \
|
||||
if (!(expr)) \
|
||||
g_warning("g_warn_if_fail: Expression '" #expr "' failed at " __FILE__ ":%d", __LINE__); \
|
||||
} while (false)
|
||||
|
||||
#define g_assert_not_reached() \
|
||||
do { \
|
||||
assert(false && "g_assert_not_reached"); \
|
||||
__builtin_unreachable(); \
|
||||
} while (false)
|
||||
|
||||
#define GLIB_SIZEOF_VOID_P 8
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE true
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
typedef bool gboolean;
|
||||
typedef char gchar;
|
||||
typedef int gint;
|
||||
typedef size_t gsize;
|
||||
typedef void* gpointer;
|
||||
|
||||
#define g_debug(format, ...) printf("[" G_LOG_DOMAIN ": debug] " format, ##__VA_ARGS__)
|
||||
#define g_warning(format, ...) printf("[" G_LOG_DOMAIN ": warning] " format, ##__VA_ARGS__)
|
||||
#define g_error(format, ...) printf("[" G_LOG_DOMAIN ": error] " format, ##__VA_ARGS__)
|
||||
#define g_critical(format, ...) printf("[" G_LOG_DOMAIN ": critical] " format, ##__VA_ARGS__)
|
||||
|
||||
#define g_new(type, count) (type*) (count > 0 ? malloc(sizeof(type) * count) : NULL)
|
||||
#define g_new0(type, count) (type*) (count > 0 ? calloc(count, sizeof(type)) : NULL)
|
||||
|
||||
#define g_malloc malloc
|
||||
#define g_malloc0(size) calloc(1, size)
|
||||
#define g_realloc realloc
|
||||
#define g_free free
|
||||
|
||||
#define g_getenv(var) getenv(var)
|
||||
|
||||
typedef struct GString {
|
||||
gchar* str;
|
||||
gsize len;
|
||||
gsize allocated_len;
|
||||
} GString;
|
||||
|
||||
typedef gchar** GStrv;
|
||||
|
||||
GString* g_string_new(gchar* initial);
|
||||
gchar* g_string_free(GString* string, gboolean free_segment);
|
||||
void g_string_append_printf(GString* gstr, const gchar* format, ...);
|
||||
gchar* g_strstr_len(const gchar* haystack, int len, const gchar* needle);
|
||||
gchar* g_strdup(const gchar* str);
|
||||
#ifdef _MSC_VER
|
||||
#define g_ascii_strcasecmp(a, b) stricmp(a, b)
|
||||
#else
|
||||
#define g_ascii_strcasecmp(a, b) strcasecmp(a, b)
|
||||
#endif
|
||||
|
||||
#define g_str_has_prefix(str, pfx) (strncmp(str, pfx, strlen(pfx)) == 0)
|
||||
#define g_snprintf snprintf
|
||||
#define g_vsnprintf vsnprintf
|
||||
|
||||
gint g_strv_length(GStrv strings);
|
||||
void g_strfreev(GStrv strings);
|
||||
|
||||
typedef uint32_t GRand;
|
||||
gint g_rand_int_range(GRand* grand, gint min, gint max);
|
||||
GRand* g_rand_new();
|
||||
void g_rand_free(GRand* rand);
|
||||
|
||||
typedef struct GError {
|
||||
const gchar* message;
|
||||
} GError;
|
||||
|
||||
void g_error_free(GError* error);
|
||||
#define g_strerror(err) strerror(err)
|
||||
|
||||
typedef void (*GSpawnChildSetupFunc)(gpointer ptr);
|
||||
typedef enum GSpawnFlags {
|
||||
G_SPAWN_SEARCH_PATH
|
||||
} GSpawnFlags;
|
||||
|
||||
typedef gint GPid;
|
||||
|
||||
gboolean g_shell_parse_argv(const gchar* command_line, gint* argcp, gchar*** argvp, GError** error);
|
||||
|
||||
gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
|
||||
gchar **envp, GSpawnFlags flags,
|
||||
GSpawnChildSetupFunc child_setup,
|
||||
gpointer user_data, GPid *child_pid, gint stdin_fd,
|
||||
gint stdout_fd, gint stderr_fd, GError **error);
|
||||
|
||||
typedef struct { gchar* key; int value; } GDebugKey;
|
||||
#define g_parse_debug_string(str, keys, nkeys) 0
|
||||
|
||||
|
||||
#endif
|
248
src/net/libslirp/meson.build
vendored
Normal file
248
src/net/libslirp/meson.build
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
project('libslirp', 'c',
|
||||
version : '4.8.0',
|
||||
license : 'BSD-3-Clause',
|
||||
default_options : ['warning_level=1', 'c_std=gnu99'],
|
||||
meson_version : '>= 0.50',
|
||||
)
|
||||
|
||||
version = meson.project_version()
|
||||
varr = version.split('.')
|
||||
major_version = varr[0]
|
||||
minor_version = varr[1]
|
||||
micro_version = varr[2]
|
||||
|
||||
conf = configuration_data()
|
||||
conf.set('SLIRP_MAJOR_VERSION', major_version)
|
||||
conf.set('SLIRP_MINOR_VERSION', minor_version)
|
||||
conf.set('SLIRP_MICRO_VERSION', micro_version)
|
||||
|
||||
want_ossfuzz = get_option('oss-fuzz')
|
||||
want_libfuzzer = get_option('llvm-fuzz')
|
||||
fuzz_reproduce = get_option('fuzz-reproduce')
|
||||
if want_ossfuzz and want_libfuzzer
|
||||
error('only one of oss-fuzz and llvm-fuzz can be specified')
|
||||
endif
|
||||
fuzzer_build = want_ossfuzz or want_libfuzzer
|
||||
if fuzzer_build and fuzz_reproduce
|
||||
error('fuzzer build and reproducer build are mutually exclusive')
|
||||
endif
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
add_languages('cpp', required : fuzzer_build)
|
||||
|
||||
if get_option('static') == true
|
||||
add_global_arguments('-static', language : 'c')
|
||||
endif
|
||||
|
||||
if cc.get_argument_syntax() != 'msvc'
|
||||
r = run_command('build-aux/git-version-gen',
|
||||
'@0@/.tarball-version'.format(meson.current_source_dir()),
|
||||
check : false)
|
||||
|
||||
full_version = r.stdout().strip()
|
||||
if r.returncode() != 0 or full_version.startswith('UNKNOWN')
|
||||
full_version = meson.project_version()
|
||||
elif not full_version.startswith(meson.project_version())
|
||||
error('meson.build project version @0@ does not match git-describe output @1@'
|
||||
.format(meson.project_version(), full_version))
|
||||
endif
|
||||
else
|
||||
full_version = meson.project_version()
|
||||
endif
|
||||
conf.set_quoted('SLIRP_VERSION_STRING', full_version + get_option('version_suffix'))
|
||||
|
||||
# libtool versioning - this applies to libslirp
|
||||
#
|
||||
# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
|
||||
#
|
||||
# - If interfaces have been changed or added, but binary compatibility
|
||||
# has been preserved, change:
|
||||
# CURRENT += 1
|
||||
# REVISION = 0
|
||||
# AGE += 1
|
||||
# - If binary compatibility has been broken (eg removed or changed
|
||||
# interfaces), change:
|
||||
# CURRENT += 1
|
||||
# REVISION = 0
|
||||
# AGE = 0
|
||||
# - If the interface is the same as the previous version, but bugs are
|
||||
# fixed, change:
|
||||
# REVISION += 1
|
||||
lt_current = 4
|
||||
lt_revision = 0
|
||||
lt_age = 4
|
||||
lt_version = '@0@.@1@.@2@'.format(lt_current - lt_age, lt_age, lt_revision)
|
||||
|
||||
host_system = host_machine.system()
|
||||
|
||||
#glib_dep = dependency('glib-2.0', static : get_option('static'))
|
||||
|
||||
glib_dep = declare_dependency(
|
||||
include_directories: [include_directories('glib', is_system: true)],
|
||||
sources: ['glib/glib.c']
|
||||
)
|
||||
|
||||
add_project_arguments(cc.get_supported_arguments('-Wmissing-prototypes', '-Wstrict-prototypes',
|
||||
'-Wredundant-decls', '-Wundef', '-Wwrite-strings'),
|
||||
language: 'c', native: false)
|
||||
|
||||
platform_deps = []
|
||||
|
||||
if host_system == 'windows'
|
||||
platform_deps += [
|
||||
cc.find_library('ws2_32'),
|
||||
cc.find_library('iphlpapi')
|
||||
]
|
||||
elif host_system == 'darwin'
|
||||
platform_deps += [
|
||||
cc.find_library('resolv')
|
||||
]
|
||||
elif host_system == 'haiku'
|
||||
platform_deps += [
|
||||
cc.find_library('network')
|
||||
]
|
||||
endif
|
||||
|
||||
cargs = [
|
||||
'-DG_LOG_DOMAIN="Slirp"',
|
||||
'-DBUILDING_LIBSLIRP',
|
||||
]
|
||||
|
||||
if cc.check_header('valgrind/valgrind.h')
|
||||
cargs += [ '-DHAVE_VALGRIND=1' ]
|
||||
endif
|
||||
|
||||
sources = [
|
||||
'src/arp_table.c',
|
||||
'src/bootp.c',
|
||||
'src/cksum.c',
|
||||
'src/dhcpv6.c',
|
||||
'src/dnssearch.c',
|
||||
'src/if.c',
|
||||
'src/ip6_icmp.c',
|
||||
'src/ip6_input.c',
|
||||
'src/ip6_output.c',
|
||||
'src/ip_icmp.c',
|
||||
'src/ip_input.c',
|
||||
'src/ip_output.c',
|
||||
'src/mbuf.c',
|
||||
'src/misc.c',
|
||||
'src/ncsi.c',
|
||||
'src/ndp_table.c',
|
||||
'src/sbuf.c',
|
||||
'src/slirp.c',
|
||||
'src/socket.c',
|
||||
'src/state.c',
|
||||
'src/stream.c',
|
||||
'src/tcp_input.c',
|
||||
'src/tcp_output.c',
|
||||
'src/tcp_subr.c',
|
||||
'src/tcp_timer.c',
|
||||
'src/tftp.c',
|
||||
'src/udp.c',
|
||||
'src/udp6.c',
|
||||
'src/util.c',
|
||||
'src/version.c',
|
||||
'src/vmstate.c',
|
||||
]
|
||||
|
||||
mapfile = 'src/libslirp.map'
|
||||
vflag = []
|
||||
vflag_test = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
|
||||
if cc.has_link_argument('-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), 'src/libslirp.test.map'))
|
||||
vflag += vflag_test
|
||||
endif
|
||||
|
||||
if fuzzer_build
|
||||
cargs += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
|
||||
cargs += '-fsanitize=fuzzer-no-link,address'
|
||||
cargs += '-fprofile-instr-generate'
|
||||
cargs += '-fcoverage-mapping'
|
||||
cargs += '-g'
|
||||
cargs += '-DSLIRP_DEBUG'
|
||||
vflag += '-fsanitize=fuzzer-no-link,address'
|
||||
vflag += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
|
||||
vflag += '-fprofile-instr-generate'
|
||||
vflag += '-fcoverage-mapping'
|
||||
endif
|
||||
if fuzz_reproduce
|
||||
cargs += '-DSLIRP_DEBUG'
|
||||
cargs += '-g'
|
||||
endif
|
||||
|
||||
install_devel = not meson.is_subproject()
|
||||
|
||||
configure_file(
|
||||
input : 'src/libslirp-version.h.in',
|
||||
output : 'libslirp-version.h',
|
||||
install : install_devel,
|
||||
install_dir : join_paths(get_option('includedir'), 'slirp'),
|
||||
configuration : conf
|
||||
)
|
||||
|
||||
if fuzzer_build or fuzz_reproduce
|
||||
lib = static_library('slirp', sources,
|
||||
c_args : cargs,
|
||||
link_args : vflag,
|
||||
link_depends : mapfile,
|
||||
dependencies : [glib_dep, platform_deps],
|
||||
)
|
||||
else
|
||||
lib = library('slirp', sources,
|
||||
version : lt_version,
|
||||
c_args : cargs,
|
||||
link_args : vflag,
|
||||
link_depends : mapfile,
|
||||
dependencies : [glib_dep, platform_deps],
|
||||
install : install_devel or get_option('default_library') == 'shared',
|
||||
)
|
||||
endif
|
||||
|
||||
pingtest = executable('pingtest', 'test/pingtest.c',
|
||||
link_with: [ lib ],
|
||||
c_args : cargs,
|
||||
link_args : vflag,
|
||||
include_directories: [ 'src' ],
|
||||
dependencies : [ platform_deps ]
|
||||
)
|
||||
|
||||
test('ping', pingtest)
|
||||
|
||||
ncsitest = executable('ncsitest', 'test/ncsitest.c',
|
||||
link_with: [lib],
|
||||
c_args : cargs,
|
||||
link_args : vflag,
|
||||
include_directories: ['src'],
|
||||
dependencies: [glib_dep, platform_deps]
|
||||
)
|
||||
|
||||
test('ncsi', ncsitest)
|
||||
|
||||
if install_devel
|
||||
install_headers(['src/libslirp.h'], subdir : 'slirp')
|
||||
|
||||
pkg = import('pkgconfig')
|
||||
|
||||
pkg.generate(
|
||||
version : version,
|
||||
libraries : lib,
|
||||
requires : [
|
||||
'glib-2.0',
|
||||
],
|
||||
name : 'slirp',
|
||||
description : 'User-space network stack',
|
||||
filebase : 'slirp',
|
||||
subdirs : 'slirp',
|
||||
)
|
||||
else
|
||||
if get_option('default_library') == 'both'
|
||||
lib = lib.get_static_lib()
|
||||
endif
|
||||
endif
|
||||
|
||||
libslirp_dep = declare_dependency(
|
||||
link_with : lib,
|
||||
include_directories : [include_directories('src'), include_directories('.')],
|
||||
)
|
||||
|
||||
subdir('fuzzing')
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user