Example #1
0
// Get the cancel object
CANCEL *VLanGetCancel(VLAN *v)
{
	CANCEL *c;
	int fd;
	int yes = 0;
	// Validate arguments
	if (v == NULL)
	{
		return NULL;
	}

	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;

	fd = v->fd;

#ifndef	UNIX_MACOS
	UnixSetSocketNonBlockingMode(fd, true);
#else	// UNIX_MACOS
	UnixSetSocketNonBlockingMode(fd, false);
#endif	// UNIX_MACOS

	c->SpecialFlag = true;
	c->pipe_read = fd;

	return c;
}
// Open Ethernet adapter (Solaris)
ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
{
	char devname[MAX_SIZE];
	UINT devid;
	int fd;
	ETH *e;
	CANCEL *c;
	struct strioctl sioc;

	// Validate arguments
	if (name == NULL || tapmode != false)
	{
		return NULL;
	}

	// Parse device name
	if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)
	{
		return NULL;
	}

	// Open the device
	fd = open(devname, O_RDWR);
	if (fd == -1)
	{
		// Failed
		return NULL;
	}

	// Attach to the device
	if (DlipAttatchRequest(fd, devid) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Verify ACK message
	if (DlipReceiveAck(fd) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Bind to SAP
	if (DlipBindRequest(fd) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Verify ACK message
	if (DlipReceiveAck(fd) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Set to ignore SAP and promiscuous mode
	if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Verify ACK message
	if (DlipReceiveAck(fd) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Set to the mode to receive self sending packet
	if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Verify ACK message
	if (DlipReceiveAck(fd) == false)
	{
		// Failed
		close(fd);
		return NULL;
	}

	// Set to raw mode
	sioc.ic_cmd = DLIOCRAW;
	sioc.ic_timout = -1;
	sioc.ic_len = 0;
	sioc.ic_dp = NULL;
	if (ioctl(fd, I_STR, &sioc) < 0)
	{
		// Failed
		close(fd);
		return NULL;
	}

	if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
	{
		// Failed
		close(fd);
		return NULL;
	}

	e = ZeroMalloc(sizeof(ETH));
	e->Name = CopyStr(name);
	e->Title = CopyStr(name);

	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;

	c->SpecialFlag = true;
	c->pipe_read = fd;

	e->Cancel = c;

	e->IfIndex = -1;
	e->Socket = fd;

	UnixSetSocketNonBlockingMode(fd, true);

	// Get control interface
	e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);

	// Get MTU value
	e->InitialMtu = EthGetMtu(e);

	return e;
}
// Open Ethernet device (Linux)
ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
{
	ETH *e;
	struct ifreq ifr;
	struct sockaddr_ll addr;
	int s;
	int index;
	CANCEL *c;
	// Validate arguments
	if (name == NULL)
	{
		return NULL;
	}

	if (tapmode)
	{
#ifndef	NO_VLAN
		// In tap mode
		VLAN *v = NewTap(name, tapaddr);
		if (v == NULL)
		{
			return NULL;
		}

		e = ZeroMalloc(sizeof(ETH));
		e->Name = CopyStr(name);
		e->Title = CopyStr(name);
		e->Cancel = VLanGetCancel(v);
		e->IfIndex = 0;
		e->Socket = INVALID_SOCKET;
		e->Tap = v;

		return e;
#else	// NO_VLAN
		return NULL;
#endif	// NO_VLAN
	}

	s = UnixEthOpenRawSocket();
	if (s == INVALID_SOCKET)
	{
		return NULL;
	}

	Zero(&ifr, sizeof(ifr));
	StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);

	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
	{
		closesocket(s);
		return NULL;
	}

	index = ifr.ifr_ifindex;

	Zero(&addr, sizeof(addr));
	addr.sll_family = PF_PACKET;
	addr.sll_protocol = htons(ETH_P_ALL);
	addr.sll_ifindex = index;

	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		closesocket(s);
		return NULL;
	}

	if (local == false)
	{
		// Enable promiscious mode
		Zero(&ifr, sizeof(ifr));
		StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
		if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
		{
			// Failed
			closesocket(s);
			return NULL;
		}

		ifr.ifr_flags |= IFF_PROMISC;

		if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
		{
			// Failed
			closesocket(s);
			return NULL;
		}
	}

	e = ZeroMalloc(sizeof(ETH));
	e->Name = CopyStr(name);
	e->Title = CopyStr(name);
	e->IfIndex = index;
	e->Socket = s;

	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;

	UnixSetSocketNonBlockingMode(s, true);

	c->SpecialFlag = true;
	c->pipe_read = s;

	e->Cancel = c;

	// Get MTU
	e->InitialMtu = EthGetMtu(e);

	if (tapmode == false)
	{
		// Disable hardware offloading
		UnixDisableInterfaceOffload(name);
	}

	return e;
}
// Open Ethernet adapter (BPF)
ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
{
	ETH *e;
	CANCEL *c;
	char devname[MAX_SIZE];
	int n = 0;
	int fd;
	int ret;
	UINT bufsize;
	struct ifreq ifr;
	struct timeval to;
	
	// Find unused bpf device and open it
	do{
		Format(devname, sizeof(devname), "/dev/bpf%d", n++);
		fd = open (devname, O_RDWR);
		if(fd<0){
			perror("open");
		}
	}while(fd < 0 && errno == EBUSY);
	
	// No free bpf device was found
	if(fd < 0){
		Debug("BPF: No minor number are free.\n");
		return NULL;
	}
	
	// Enlarge buffer size
	n = 524288; // Somehow(In libpcap, this size is 32768)
	while(true){
		// Specify buffer size
		ioctl(fd, BIOCSBLEN, &n);

		// Bind to the network device
		StrCpy(ifr.ifr_name, IFNAMSIZ, name);
		ret = ioctl(fd, BIOCSETIF, &ifr);
		if(ret < 0){
			if(ret == ENOBUFS && n>1500){
				// Inappropriate buffer size
				// Retry with half buffer size
				// If buffer size is under 1500 bytes, something goes wrong
				n /= 2;
				continue;
			}
			Debug("bpf: binding network failed.\n");
			close(fd);
			return NULL;
		}else{
			break;
		}
	}
	bufsize = n;

	// Set to promiscuous mode
	if(local == false){
		if (ioctl(fd, BIOCPROMISC, NULL) < 0){
			printf("bpf: promisc mode failed.\n");
			close(fd);
			return NULL;
		}
	}

	
	// Set to immediate mode (Return immediately when packet arrives)
	n = 1;
	if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){
		Debug("BPF: non-block mode failed.\n");
		close(fd);
		return NULL;
	}

	// Set receiving self sending packet
	n = 1;
	if (ioctl(fd, BIOCGSEESENT, &n) < 0){
		Debug("BPF: see sent mode failed.\n");
		close(fd);
		return NULL;
	}

	// Header complete mode (Generate whole header of sending packet)
	n = 1;
	if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){
		Debug("BPF: Header complete mode failed.\n");
		close(fd);
		return NULL;
	}
	
	// Set timeout delay to 1 second
	to.tv_sec = 1;
	to.tv_usec = 0;
	if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){
		Debug("BPF: Read timeout setting failed.\n");
		close(fd);
		return NULL;
	}
	
	e = ZeroMalloc(sizeof(ETH));
	e->Name = CopyStr(name);
	e->Title = CopyStr(name);
	e->IfIndex = -1;
	e->Socket = fd;
	e->BufSize = bufsize;

#ifdef BRIDGE_BPF_THREAD
	e->Queue = NewQueue();
	e->QueueSize = 0;
	e->Cancel = NewCancel();

	// Start capture thread
	e->CaptureThread = NewThread(BpfThread, e);
	WaitThreadInit(e->CaptureThread);

#else // BRIDGE_BPF_THREAD
	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;
	c->SpecialFlag = true;
	c->pipe_read = fd;
	e->Cancel = c;
	e->Buffer = Malloc(bufsize);
	e->Next = e->Buffer;
	e->Rest = 0;

	// Set to non-blocking mode
	UnixSetSocketNonBlockingMode(fd, true);
#endif // BRIDGE_BPF_THREAD

	// Open interface control socket for FreeBSD
	e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);

	// Get MTU value
	e->InitialMtu = EthGetMtu(e);

	return e;
}
Example #5
0
// アダプタを開く (Solaris)
ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
{
	char devname[MAX_SIZE];
	UINT devid;
	int fd;
	ETH *e;
	CANCEL *c;
	struct strioctl sioc;

	// 引数チェック
	if (name == NULL || tapmode != false)
	{
		return NULL;
	}

	// デバイス名を解析
	if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)
	{
		return NULL;
	}

	// デバイスを開く
	fd = open(devname, O_RDWR);
	if (fd == -1)
	{
		// 失敗
		return NULL;
	}

	// デバイスにアタッチする
	if (DlipAttatchRequest(fd, devid) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// 確認
	if (DlipReceiveAck(fd) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// SAPにバインドする
	if (DlipBindRequest(fd) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// 確認
	if (DlipReceiveAck(fd) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// SAPに関わらず受信するモードにセットする
	if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// 確認
	if (DlipReceiveAck(fd) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// 自分の送信するパケットも受信するモードにセットする
	if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// 確認
	if (DlipReceiveAck(fd) == false)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	// Raw モードに設定
	sioc.ic_cmd = DLIOCRAW;
	sioc.ic_timout = -1;
	sioc.ic_len = 0;
	sioc.ic_dp = NULL;
	if (ioctl(fd, I_STR, &sioc) < 0)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
	{
		// 失敗
		close(fd);
		return NULL;
	}

	e = ZeroMalloc(sizeof(ETH));
	e->Name = CopyStr(name);
	e->Title = CopyStr(name);

	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;

	c->SpecialFlag = true;
	c->pipe_read = fd;

	e->Cancel = c;

	e->IfIndex = -1;
	e->Socket = fd;

	UnixSetSocketNonBlockingMode(fd, true);

	// 操作用 I/F の取得
	e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);

	// MTU の取得
	e->InitialMtu = EthGetMtu(e);

	return e;
}
Example #6
0
// アダプタを開く (BPF)
ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
{
	ETH *e;
	CANCEL *c;
	char devname[MAX_SIZE];
	int n = 0;
	int fd;
	int ret;
	UINT bufsize;
	struct ifreq ifr;
	struct timeval to;
	
	// 未使用の bpf デバイスを探して開く
	do{
		Format(devname, sizeof(devname), "/dev/bpf%d", n++);
		fd = open (devname, O_RDWR);
		if(fd<0){
			perror("open");
		}
	}while(fd < 0 && errno == EBUSY);
	
	// 開くことが出来るbpfデバイスが無ければエラー
	if(fd < 0){
		Debug("BPF: No minor number are free.\n");
		return NULL;
	}
	
	// バッファサイズを拡大
	n = 524288; // なんとなく(libpcapでは32768だった)
	while(true){
		// バッファサイズを指定
		ioctl(fd, BIOCSBLEN, &n);

		// ネットワークをバインド
		StrCpy(ifr.ifr_name, IFNAMSIZ, name);
		ret = ioctl(fd, BIOCSETIF, &ifr);
		if(ret < 0){
			if(ret == ENOBUFS && n>1500){
				// バッファサイズが不適切
				// サイズを半分にしてリトライ
				// バッファサイズ1500バイト以下でエラーになるのは何かおかしい
				n /= 2;
				continue;
			}
			Debug("bpf: binding network failed.\n");
			close(fd);
			return NULL;
		}else{
			break;
		}
	}
	bufsize = n;

	// プロミスキャスモードに設定
	if(local == false){
		if (ioctl(fd, BIOCPROMISC, NULL) < 0){
			printf("bpf: promisc mode failed.\n");
			close(fd);
			return NULL;
		}
	}

	
	// 即時モードに設定(パケットを受信するとタイムアウトを待たず、すぐにreadがreturnする)
	n = 1;
	if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){
		Debug("BPF: non-block mode failed.\n");
		close(fd);
		return NULL;
	}

	// 自分が送信するパケットも受信する
	n = 1;
	if (ioctl(fd, BIOCGSEESENT, &n) < 0){
		Debug("BPF: see sent mode failed.\n");
		close(fd);
		return NULL;
	}


	// ヘッダ完全モード(送信するパケットのヘッダも自分で生成する)
	n = 1;
	if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){
		Debug("BPF: Header complete mode failed.\n");
		close(fd);
		return NULL;
	}
	
	// read のタイムアウト時間を設定(1秒)
	to.tv_sec = 1;
	to.tv_usec = 0;
	if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){
		Debug("BPF: Read timeout setting failed.\n");
		close(fd);
		return NULL;
	}
	
	e = ZeroMalloc(sizeof(ETH));
	e->Name = CopyStr(name);
	e->Title = CopyStr(name);
	e->IfIndex = -1;
	e->Socket = fd;
	e->BufSize = bufsize;

#ifdef BRIDGE_BPF_THREAD
	e->Queue = NewQueue();
	e->QueueSize = 0;
	e->Cancel = NewCancel();

	// キャプチャ用スレッドの開始
	e->CaptureThread = NewThread(BpfThread, e);
	WaitThreadInit(e->CaptureThread);

#else // BRIDGE_BPF_THREAD
	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;
	c->SpecialFlag = true;
	c->pipe_read = fd;
	e->Cancel = c;
	e->Buffer = Malloc(bufsize);
	e->Next = e->Buffer;
	e->Rest = 0;

	// ノンブロッキングモードに設定
	UnixSetSocketNonBlockingMode(fd, true);
#endif // BRIDGE_BPF_THREAD

	// FreeBSD 用インターフェイス操作用ソケットを作成
	e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);

	// MTU の取得
	e->InitialMtu = EthGetMtu(e);

	return e;
}
Example #7
0
// Open Ethernet device (Linux)
ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
{
	ETH *e;
	struct ifreq ifr;
	struct sockaddr_ll addr;
	int s;
	int index;
	bool aux_ok = false;
	CANCEL *c;
	// Validate arguments
	if (name == NULL)
	{
		return NULL;
	}

	if (tapmode)
	{
#ifndef	NO_VLAN
		// In tap mode
		VLAN *v = NewTap(name, tapaddr);
		if (v == NULL)
		{
			return NULL;
		}

		e = ZeroMalloc(sizeof(ETH));
		e->Name = CopyStr(name);
		e->Title = CopyStr(name);
		e->Cancel = VLanGetCancel(v);
		e->IfIndex = 0;
		e->Socket = INVALID_SOCKET;
		e->Tap = v;

		return e;
#else	// NO_VLAN
		return NULL;
#endif	// NO_VLAN
	}

	s = UnixEthOpenRawSocket();
	if (s == INVALID_SOCKET)
	{
		return NULL;
	}

	Zero(&ifr, sizeof(ifr));
	StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);

	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
	{
		closesocket(s);
		return NULL;
	}

	index = ifr.ifr_ifindex;

	Zero(&addr, sizeof(addr));
	addr.sll_family = PF_PACKET;
	addr.sll_protocol = htons(ETH_P_ALL);
	addr.sll_ifindex = index;

	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		closesocket(s);
		return NULL;
	}

	if (local == false)
	{
		// Enable promiscious mode
		Zero(&ifr, sizeof(ifr));
		StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
		if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
		{
			// Failed
			closesocket(s);
			return NULL;
		}

		ifr.ifr_flags |= IFF_PROMISC;

		if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
		{
			// Failed
			closesocket(s);
			return NULL;
		}
	}

	if (true)
	{
		int val = 1;
		int ss_ret = setsockopt(s, SOL_PACKET, MY_PACKET_AUXDATA, &val, sizeof(val));

		if (ss_ret < 0)
		{
			Debug("eth(%s): setsockopt: PACKET_AUXDATA failed.\n", name);
		}
		else
		{
			Debug("eth(%s): setsockopt: PACKET_AUXDATA ok.\n", name);
			aux_ok = true;
		}
	}

	e = ZeroMalloc(sizeof(ETH));
	e->Name = CopyStr(name);
	e->Title = CopyStr(name);
	e->IfIndex = index;
	e->Socket = s;

	e->Linux_IsAuxDataSupported = aux_ok;

	c = NewCancel();
	UnixDeletePipe(c->pipe_read, c->pipe_write);
	c->pipe_read = c->pipe_write = -1;

	UnixSetSocketNonBlockingMode(s, true);

	c->SpecialFlag = true;
	c->pipe_read = s;

	e->Cancel = c;

	// Get MTU
	e->InitialMtu = EthGetMtu(e);

	if (tapmode == false)
	{
		if (GetGlobalServerFlag(GSF_LOCALBRIDGE_NO_DISABLE_OFFLOAD) == false)
		{
			bool b = false;

			LockList(eth_offload_list);
			{
				if (IsInListStr(eth_offload_list, name) == false)
				{
					b = true;

					Add(eth_offload_list, CopyStr(name));
				}
			}
			UnlockList(eth_offload_list);

			if (b)
			{
				// Disable hardware offloading
				UnixDisableInterfaceOffload(name);
			}
		}
	}

	return e;
}