Last active
November 26, 2019 13:24
-
-
Save shun159/4378c0fbb9870be5a1bc2cdecd72d8f4 to your computer and use it in GitHub Desktop.
内容はテキトーなんで許してちょんまげ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(bridge). | |
-export([start/2]). | |
-define(SIOCGIFINDEX, 16#8933). | |
-define(ETH_P_ALL, 16#0300). | |
start(Iface1, Iface2) -> | |
S1 = bind(Iface1), | |
S2 = bind(Iface2), | |
spawn(fun() -> loop(S1, S2) end), | |
spawn(fun() -> loop(S2, S1) end). | |
loop(Src, Dst) -> | |
case socket:recv(Src) of | |
{error, _} -> | |
loop(Src, Dst); | |
{ok, Pkt} -> | |
_ = socket:send(Dst, Pkt), | |
loop(Src, Dst) | |
end. | |
%% private functions | |
bind(Iface) -> | |
{ok, S} = socket:open(packet, raw, {raw, ?ETH_P_ALL}), | |
{ok, 0} = socket:bind(S, sockaddr_ll(ifindex_of(S, Iface))), | |
S. | |
ifindex_of(S, Iface) -> | |
{ok, Return} = socket:ioctl(S, ?SIOCGIFINDEX, ifreq(Iface)), | |
<<_Ifname:16/bytes, Ifr:32/native, _/binary>> = Return, | |
Ifr. | |
sockaddr_ll(Ifr) -> | |
#{ | |
family => packet, | |
protocol => 0, | |
ifindex => Ifr, | |
hatype => 0, | |
pkttype => 0, | |
halen => 0, | |
addr => <<0:64>> | |
}. | |
ifreq(Dev) -> | |
list_to_binary( | |
[ | |
Dev, | |
<<0:((15*8) - (length(Dev)*8)), 0:8, 0:128>> | |
] | |
). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in | |
index 7f50372532..8874125618 100644 | |
--- a/erts/emulator/Makefile.in | |
+++ b/erts/emulator/Makefile.in | |
@@ -232,7 +232,7 @@ endif | |
OPSYS=@OPSYS@ | |
sol2CFLAGS= | |
-linuxCFLAGS= | |
+linuxCFLAGS=-Wall -g | |
darwinCFLAGS=-DDARWIN | |
noopsysCFLAGS= | |
OPSYSCFLAGS=$($(OPSYS)CFLAGS) | |
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h | |
index 4161775a04..63fec2b5e3 100644 | |
--- a/erts/emulator/nifs/common/socket_int.h | |
+++ b/erts/emulator/nifs/common/socket_int.h | |
@@ -54,6 +54,7 @@ | |
#else /* !__WIN32__ */ | |
+#include <netpacket/packet.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#ifdef HAVE_SYS_UN_H | |
@@ -82,6 +83,9 @@ typedef union { | |
struct sockaddr_un un; | |
#endif | |
+ /* Link-Layer sockaddr */ | |
+ struct sockaddr_ll ll; | |
+ | |
} ESockAddress; | |
@@ -303,7 +307,12 @@ typedef unsigned int BOOLEAN_T; | |
GLOBAL_ATOM_DEF(user_timeout); \ | |
GLOBAL_ATOM_DEF(use_ext_recvinfo); \ | |
GLOBAL_ATOM_DEF(use_min_mtu); \ | |
- GLOBAL_ATOM_DEF(v6only); | |
+ GLOBAL_ATOM_DEF(v6only); \ | |
+ GLOBAL_ATOM_DEF(protocol); \ | |
+ GLOBAL_ATOM_DEF(hatype); \ | |
+ GLOBAL_ATOM_DEF(pkttype); \ | |
+ GLOBAL_ATOM_DEF(halen); \ | |
+ GLOBAL_ATOM_DEF(packet); | |
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c | |
index bbeb8b6cdd..cfa0c7e3b1 100644 | |
--- a/erts/emulator/nifs/common/socket_nif.c | |
+++ b/erts/emulator/nifs/common/socket_nif.c | |
@@ -528,6 +528,7 @@ typedef union { | |
#define ESOCK_DOMAIN_LOCAL 1 | |
#define ESOCK_DOMAIN_INET 2 | |
#define ESOCK_DOMAIN_INET6 3 | |
+#define ESOCK_DOMAIN_PACKET 4 | |
/* type */ | |
#define ESOCK_TYPE_STREAM 1 | |
@@ -2888,7 +2889,11 @@ static char str_exsend[] = "exsend"; // failed send | |
GLOBAL_ATOM_DECL(user_timeout); \ | |
GLOBAL_ATOM_DECL(use_ext_recvinfo); \ | |
GLOBAL_ATOM_DECL(use_min_mtu); \ | |
- GLOBAL_ATOM_DECL(v6only); | |
+ GLOBAL_ATOM_DECL(v6only); \ | |
+ GLOBAL_ATOM_DECL(hatype); \ | |
+ GLOBAL_ATOM_DECL(pkttype); \ | |
+ GLOBAL_ATOM_DECL(halen); \ | |
+ GLOBAL_ATOM_DECL(packet); | |
/* *** Global error reason atoms *** */ | |
@@ -4740,7 +4745,37 @@ ERL_NIF_TERM esock_supports_local(ErlNifEnv* env) | |
} | |
#endif | |
+static | |
+ERL_NIF_TERM nif_ioctl(ErlNifEnv* env, | |
+ int argc, | |
+ const ERL_NIF_TERM argv[]) | |
+{ | |
+#if defined(__WIN32__) | |
+ return enif_raise_exception(env, MKA(env, "notsup")); | |
+#else | |
+ ESockDescriptor* descP; | |
+ ERL_NIF_TERM sockRef, res; | |
+ ErlNifBinary arg; | |
+ int req = 0; | |
+ | |
+ sockRef = argv[0]; | |
+ if (!enif_get_int(env, argv[1], &req) | |
+ || !enif_inspect_binary(env, argv[2], &arg) | |
+ || !ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) | |
+ return enif_make_badarg(env); | |
+ | |
+ MLOCK(descP->readMtx); | |
+ | |
+ if (ioctl(descP->sock, req, arg.data) < 0) | |
+ res = esock_make_error_errno(env, sock_errno()); | |
+ res = enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &arg)); | |
+ | |
+ MUNLOCK(descP->readMtx); | |
+ | |
+ return res; | |
+#endif // if defined(__WIN32__) | |
+} | |
/* ---------------------------------------------------------------------- | |
* nif_open | |
@@ -4766,9 +4801,10 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, | |
#if defined(__WIN32__) | |
return enif_raise_exception(env, MKA(env, "notsup")); | |
#else | |
- int edomain, etype, eproto; | |
+ int edomain, etype; | |
int domain, type, proto; | |
char* netns; | |
+ ERL_NIF_TERM eproto; | |
ERL_NIF_TERM emap; | |
ERL_NIF_TERM result; | |
@@ -4932,7 +4968,7 @@ ERL_NIF_TERM esock_open(ErlNifEnv* env, | |
/* Does this apply to other types? Such as RAW? | |
* Also, is this really correct? Should we not wait for bind? | |
*/ | |
- if (type == SOCK_DGRAM) { | |
+ if (type == SOCK_DGRAM || type == SOCK_RAW) { | |
descP->isReadable = TRUE; | |
descP->isWritable = TRUE; | |
} | |
@@ -5145,7 +5181,7 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, | |
*/ | |
if (descP->state != ESOCK_STATE_OPEN) | |
return esock_make_error(env, atom_exbadstate); | |
- | |
+ | |
if ((xres = esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen)) != NULL) | |
return esock_make_error_str(env, xres); | |
@@ -17694,6 +17730,12 @@ BOOLEAN_T edomain2domain(int edomain, int* domain) | |
*domain = AF_INET; | |
break; | |
+#if defined(AF_PACKET) | |
+ case ESOCK_DOMAIN_PACKET: | |
+ *domain = AF_PACKET; | |
+ break; | |
+#endif | |
+ | |
#if defined(HAVE_IN6) && defined(AF_INET6) | |
case ESOCK_DOMAIN_INET6: | |
*domain = AF_INET6; | |
@@ -17809,7 +17851,7 @@ BOOLEAN_T eproto2proto(ErlNifEnv* env, | |
*proto = -3; | |
return FALSE; | |
} | |
- | |
+ | |
if (sz != 2) { | |
*proto = -4; | |
return FALSE; | |
@@ -19575,6 +19617,7 @@ ErlNifFunc esock_funcs[] = | |
// The proper "socket" interface | |
// nif_open/1 is (supposed to be) used when we already have a file descriptor | |
// {"nif_open", 1, nif_open, 0}, | |
+ {"nif_ioctl", 3, nif_ioctl, 0}, | |
{"nif_open", 4, nif_open, 0}, | |
{"nif_bind", 2, nif_bind, 0}, | |
{"nif_connect", 2, nif_connect, 0}, | |
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c | |
index 54c310ecc7..a065daf9af 100644 | |
--- a/erts/emulator/nifs/common/socket_util.c | |
+++ b/erts/emulator/nifs/common/socket_util.c | |
@@ -73,7 +73,14 @@ static char* make_sockaddr_in6(ErlNifEnv* env, | |
static char* make_sockaddr_un(ErlNifEnv* env, | |
ERL_NIF_TERM path, | |
ERL_NIF_TERM* sa); | |
- | |
+static char* make_sockaddr_ll(ErlNifEnv* env, | |
+ ERL_NIF_TERM protocol, | |
+ ERL_NIF_TERM ifindex, | |
+ ERL_NIF_TERM hatype, | |
+ ERL_NIF_TERM pkttype, | |
+ ERL_NIF_TERM halen, | |
+ ERL_NIF_TERM addr, | |
+ ERL_NIF_TERM* sa); | |
/* +++ esock_encode_iov +++ | |
* | |
@@ -243,6 +250,11 @@ char* esock_decode_sockaddr(ErlNifEnv* env, | |
&sockAddrP->in4, addrLen); | |
break; | |
+ case AF_PACKET: | |
+ xres = esock_decode_sockaddr_ll(env, eSockAddr, | |
+ &sockAddrP->ll, addrLen); | |
+ break; | |
+ | |
#if defined(HAVE_IN6) && defined(AF_INET6) | |
case AF_INET6: | |
xres = esock_decode_sockaddr_in6(env, eSockAddr, | |
@@ -298,6 +310,10 @@ char* esock_encode_sockaddr(ErlNifEnv* env, | |
xres = esock_encode_sockaddr_in4(env, &sockAddrP->in4, addrLen, eSockAddr); | |
break; | |
+ case AF_PACKET: | |
+ xres = esock_encode_sockaddr_ll(env, &sockAddrP->ll, addrLen, eSockAddr); | |
+ break; | |
+ | |
#if defined(HAVE_IN6) && defined(AF_INET6) | |
case AF_INET6: | |
xres = esock_encode_sockaddr_in6(env, &sockAddrP->in6, addrLen, eSockAddr); | |
@@ -387,8 +403,6 @@ char* esock_decode_sockaddr_in4(ErlNifEnv* env, | |
return NULL; | |
} | |
- | |
- | |
/* +++ esock_encode_sockaddr_in4 +++ | |
* | |
* Encode a IPv4 socket address - sockaddr_in4. In erlang its represented as | |
@@ -715,7 +729,145 @@ char* esock_encode_sockaddr_un(ErlNifEnv* env, | |
} | |
#endif | |
+/* +++ esock_decode_sockaddr_ll +++ | |
+ * | |
+ * Decode a Link-layer address - sockaddr_ll. In erlang its | |
+ * represented as a map, which has a specific set of attributes | |
+ * (beside the mandatory family attribute, which is "inherited" from "sockaddr" type): | |
+ * | |
+ * protocol :: non_neg_integer() | |
+ * ifindex :: non_neg_integer() | |
+ * hatype :: non_neg_integer() | |
+ * pkttype :: non_neg_integer() | |
+ * halen :: non_neg_integer() | |
+ * addr :: <<_:64>> | |
+ */ | |
+ | |
+extern | |
+char* esock_decode_sockaddr_ll(ErlNifEnv* env, | |
+ ERL_NIF_TERM eSockAddr, | |
+ struct sockaddr_ll* sockAddrP, | |
+ unsigned int* addrLen) | |
+{ | |
+ ERL_NIF_TERM eproto, eifindex, ehatype, epkttype, ehalen, eaddr; | |
+ int ifindex; | |
+ unsigned int proto, hatype, pkttype, halen; | |
+ ErlNifBinary addr; | |
+ | |
+ /* Basic init */ | |
+ sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_ll)); | |
+ | |
+ /* sll_family always AF_PACKET */ | |
+ sockAddrP->sll_family = AF_PACKET; | |
+ | |
+ /* *** Extract protocol number from map *** */ | |
+ if (!GET_MAP_VAL(env, eSockAddr, esock_atom_protocol, &eproto)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ /* Decode protocol number */ | |
+ if (!GET_UINT(env, eproto, &proto)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ sockAddrP->sll_protocol = htons(proto); | |
+ | |
+ /* *** Extract ifindex from map *** */ | |
+ if (!GET_MAP_VAL(env, eSockAddr, esock_atom_ifindex, &eifindex)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ /* Decode ifindex */ | |
+ if (!GET_INT(env, eifindex, &ifindex)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ sockAddrP->sll_ifindex = ifindex; | |
+ | |
+ /* *** Extract hatype from map *** */ | |
+ if (!GET_MAP_VAL(env, eSockAddr, esock_atom_hatype, &ehatype)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ /* Decode hatype */ | |
+ if (!GET_UINT(env, ehatype, &hatype)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ sockAddrP->sll_hatype = hatype; | |
+ | |
+ /* *** Extract pkttype from map *** */ | |
+ if (!GET_MAP_VAL(env, eSockAddr, esock_atom_pkttype, &epkttype)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ /* Decode pkttype */ | |
+ if (!GET_UINT(env, epkttype, &pkttype)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ sockAddrP->sll_pkttype = pkttype; | |
+ | |
+ /* *** Extract halen from map *** */ | |
+ if (!GET_MAP_VAL(env, eSockAddr, esock_atom_halen, &ehalen)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ /* Decode halen */ | |
+ if (!GET_UINT(env, ehalen, &halen)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ sockAddrP->sll_halen = halen; | |
+ | |
+ /* *** Extract addr from map *** */ | |
+ if (!GET_MAP_VAL(env, eSockAddr, esock_atom_addr, &eaddr)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ /* Get the addr */ | |
+ if (!GET_BIN(env, eaddr, &addr)) | |
+ return ESOCK_STR_EINVAL; | |
+ | |
+ sys_memcpy(sockAddrP->sll_addr, addr.data, addr.size); | |
+ *addrLen = sizeof(struct sockaddr_ll); | |
+ | |
+ return NULL; | |
+} | |
+ | |
+extern | |
+char* esock_encode_sockaddr_ll(ErlNifEnv* env, | |
+ struct sockaddr_ll* sockAddrP, | |
+ unsigned int addrLen, | |
+ ERL_NIF_TERM* eSockAddr) | |
+{ | |
+ ERL_NIF_TERM eProto, eIfindex, eHatype, ePkttype, eHalen, eAddr; | |
+ char* xres; | |
+ | |
+ if (addrLen >= sizeof(struct sockaddr_ll)) { | |
+ /* The protocol */ | |
+ eProto = MKI(env, sockAddrP->sll_protocol); | |
+ | |
+ /* The ifindex */ | |
+ eIfindex = MKI(env, sockAddrP->sll_ifindex); | |
+ | |
+ /* The hatype */ | |
+ eHatype = MKI(env, sockAddrP->sll_pkttype); | |
+ | |
+ /* The pkttype */ | |
+ ePkttype = MKI(env, sockAddrP->sll_pkttype); | |
+ | |
+ /* The halen */ | |
+ eHalen = MKI(env, sockAddrP->sll_halen); | |
+ | |
+ /* The addr */ | |
+ eAddr = MKBIN(env, &(sockAddrP->sll_addr)); | |
+ | |
+ /* And finally construct the ll_sockaddr record */ | |
+ xres = make_sockaddr_ll(env, | |
+ eProto, | |
+ eIfindex, | |
+ eHatype, | |
+ ePkttype, | |
+ eHalen, | |
+ eAddr, | |
+ eSockAddr); | |
+ } else { | |
+ *eSockAddr = esock_atom_undefined; | |
+ xres = ESOCK_STR_EINVAL; | |
+ } | |
+ return xres; | |
+} | |
/* +++ esock_decode_ip4_address +++ | |
* | |
@@ -932,8 +1084,6 @@ char* esock_encode_ip6_address(ErlNifEnv* env, | |
} | |
#endif | |
- | |
- | |
/* +++ esock_encode_timeval +++ | |
* | |
* Encode a timeval struct into its erlang form, a map with two fields: | |
@@ -1049,6 +1199,9 @@ char* esock_decode_domain(ErlNifEnv* env, | |
*domain = AF_UNIX; | |
#endif | |
+ } else if (COMPARE(esock_atom_packet, eDomain) == 0) { | |
+ *domain = AF_PACKET; | |
+ | |
} else { | |
*domain = -1; | |
xres = ESOCK_STR_EAFNOSUPPORT; | |
@@ -1092,6 +1245,10 @@ char* esock_encode_domain(ErlNifEnv* env, | |
break; | |
#endif | |
+ case AF_PACKET: | |
+ *eDomain = esock_atom_packet; | |
+ break; | |
+ | |
default: | |
*eDomain = esock_atom_undefined; // Just in case | |
xres = ESOCK_STR_EAFNOSUPPORT; | |
@@ -1697,3 +1854,34 @@ char* make_sockaddr_un(ErlNifEnv* env, | |
} | |
+/* Construct the Link Layer socket address */ | |
+static | |
+char* make_sockaddr_ll(ErlNifEnv* env, | |
+ ERL_NIF_TERM protocol, | |
+ ERL_NIF_TERM ifindex, | |
+ ERL_NIF_TERM hatype, | |
+ ERL_NIF_TERM pkttype, | |
+ ERL_NIF_TERM halen, | |
+ ERL_NIF_TERM addr, | |
+ ERL_NIF_TERM* sa) | |
+{ | |
+ ERL_NIF_TERM keys[] = {esock_atom_protocol, | |
+ esock_atom_ifindex, | |
+ esock_atom_hatype, | |
+ esock_atom_pkttype, | |
+ esock_atom_halen, | |
+ esock_atom_addr}; | |
+ ERL_NIF_TERM vals[] = {protocol, ifindex, hatype, pkttype, halen, addr}; | |
+ | |
+ unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM); | |
+ unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM); | |
+ | |
+ ESOCK_ASSERT( (numKeys == numVals) ); | |
+ | |
+ if (!MKMA(env, keys, vals, numKeys, sa)) { | |
+ *sa = esock_atom_undefined; | |
+ return ESOCK_STR_EINVAL; | |
+ } else { | |
+ return NULL; | |
+ } | |
+} | |
diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h | |
index 2688a920c4..57da3f522c 100644 | |
--- a/erts/emulator/nifs/common/socket_util.h | |
+++ b/erts/emulator/nifs/common/socket_util.h | |
@@ -104,6 +104,18 @@ char* esock_encode_sockaddr_un(ErlNifEnv* env, | |
ERL_NIF_TERM* eSockAddr); | |
#endif | |
+extern | |
+char* esock_decode_sockaddr_ll(ErlNifEnv* env, | |
+ ERL_NIF_TERM eSockAddr, | |
+ struct sockaddr_ll* sockAddrP, | |
+ unsigned int* addrLen); | |
+ | |
+extern | |
+char* esock_encode_sockaddr_ll(ErlNifEnv* env, | |
+ struct sockaddr_ll* sockAddrP, | |
+ unsigned int addrLen, | |
+ ERL_NIF_TERM* eSockAddr); | |
+ | |
extern | |
char* esock_decode_ip4_address(ErlNifEnv* env, | |
ERL_NIF_TERM eAddr, | |
@@ -124,6 +136,12 @@ char* esock_encode_ip6_address(ErlNifEnv* env, | |
ERL_NIF_TERM* eAddr); | |
#endif | |
+extern | |
+char* esock_decode_ll_address(ErlNifEnv* env, | |
+ ERL_NIF_TERM eAddr, | |
+ unsigned int halen, | |
+ unsigned char* llAddrP); | |
+ | |
extern char* esock_encode_timeval(ErlNifEnv* env, | |
struct timeval* timeP, | |
ERL_NIF_TERM* eTime); | |
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam | |
index 73a0bd4f72..38a41307b7 100644 | |
Binary files a/erts/preloaded/ebin/socket.beam and b/erts/preloaded/ebin/socket.beam differ | |
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl | |
index 07e720c44d..99bbe13139 100644 | |
--- a/erts/preloaded/src/socket.erl | |
+++ b/erts/preloaded/src/socket.erl | |
@@ -37,6 +37,7 @@ | |
-export([ | |
open/2, open/3, open/4, | |
+ ioctl/3, | |
bind/2, bind/3, | |
connect/2, connect/3, | |
listen/1, listen/2, | |
@@ -320,9 +321,16 @@ | |
addr := any | loopback | ip6_address(), | |
flowinfo := in6_flow_info(), | |
scope_id := in6_scope_id()}. | |
+-type sockaddr_ll() :: #{family := packet, | |
+ ifindex := integer(), | |
+ hatype := non_neg_integer(), | |
+ pkttype := non_neg_integer(), | |
+ halen := non_neg_integer(), | |
+ addr := binary()}. | |
-type sockaddr() :: sockaddr_in4() | | |
sockaddr_in6() | | |
- sockaddr_un(). | |
+ sockaddr_un() | | |
+ sockaddr_ll(). | |
-define(SOCKADDR_IN4_DEFAULTS(A), #{port => 0, | |
addr => A}). | |
@@ -334,6 +342,13 @@ | |
scope_id => 0}). | |
-define(SOCKADDR_IN6_DEFAULTS, ?SOCKADDR_IN6_DEFAULTS(any)). | |
-define(SOCKADDR_IN6_DEFAULT(A), (?SOCKADDR_IN6_DEFAULTS(A))#{family => inet6}). | |
+-define(SOCKADDR_LL_DEFAULTS(Ifindex), #{ifindex => IfIndex, | |
+ hatype => 0, | |
+ pkttype => 0, | |
+ halen => 0, | |
+ addr => <<0:64>>}). | |
+-define(SOCKADDR_LL_DEFAULTS, ?SOCKADDR_LL_DEFAULTS(0)). | |
+-define(SOCKADDR_LL_DEFAULT(Ifindex), (?SOCKADDR_LL_DEFAULTS(Ifindex))#{family => packet}). | |
%% otp - This option is internal to our (OTP) implementation. | |
%% socket - The socket layer (SOL_SOCKET). | |
@@ -641,10 +656,11 @@ | |
%% | |
-define(SOCKET_TAG, '$socket'). | |
--define(SOCKET_DOMAIN_LOCAL, 1). | |
--define(SOCKET_DOMAIN_UNIX, ?SOCKET_DOMAIN_LOCAL). | |
--define(SOCKET_DOMAIN_INET, 2). | |
--define(SOCKET_DOMAIN_INET6, 3). | |
+-define(SOCKET_DOMAIN_LOCAL, 1). | |
+-define(SOCKET_DOMAIN_UNIX, ?SOCKET_DOMAIN_LOCAL). | |
+-define(SOCKET_DOMAIN_INET, 2). | |
+-define(SOCKET_DOMAIN_INET6, 3). | |
+-define(SOCKET_DOMAIN_PACKET, 4). | |
-define(SOCKET_TYPE_STREAM, 1). | |
-define(SOCKET_TYPE_DGRAM, 2). | |
@@ -1143,6 +1159,15 @@ open(Domain, Type, Protocol, Extra) when is_map(Extra) -> | |
end. | |
+-spec(ioctl(Socket, Request, Arg) -> {ok, binary()} | {error, Reason} when | |
+ Socket :: socket(), | |
+ Request :: 0..16#ffff, | |
+ Arg :: binary(), | |
+ Reason :: term()). | |
+ioctl(#socket{ref = SockRef}, Request, Arg) | |
+ when is_integer(Request), | |
+ is_binary(Arg) -> | |
+ nif_ioctl(SockRef, Request, Arg). | |
%% =========================================================================== | |
%% | |
@@ -1305,7 +1330,7 @@ connect(_Socket, _SockAddr, Timeout) | |
when (is_integer(Timeout) andalso (Timeout =< 0)) -> | |
{error, timeout}; | |
connect(#socket{ref = SockRef}, #{family := Fam} = SockAddr, Timeout) | |
- when ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso | |
+ when ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) orelse (Fam =:= packet) andalso | |
((Timeout =:= nowait) orelse | |
(Timeout =:= infinity) orelse is_integer(Timeout)) -> | |
TS = timestamp(Timeout), | |
@@ -2702,6 +2727,7 @@ cancel(#socket{ref = SockRef}, ?SELECT_INFO(Tag, Ref)) -> | |
enc_domain(local) -> ?SOCKET_DOMAIN_LOCAL; | |
enc_domain(inet) -> ?SOCKET_DOMAIN_INET; | |
enc_domain(inet6) -> ?SOCKET_DOMAIN_INET6; | |
+enc_domain(packet) -> ?SOCKET_DOMAIN_PACKET; | |
enc_domain(Domain) -> invalid_domain(Domain). | |
%% -spec enc_type(Domain, Type) -> non_neg_integer() when | |
@@ -3763,6 +3789,10 @@ ensure_sockaddr(#{family := local, path := Path} = SockAddr) | |
(byte_size(Path) > 0) andalso | |
(byte_size(Path) =< 255) -> | |
SockAddr; | |
+ensure_sockaddr(#{family := packet, addr := Addr} = SockAddr) | |
+ when is_binary(Addr), | |
+ byte_size(Addr) == 8 -> | |
+ SockAddr; | |
ensure_sockaddr(_SockAddr) -> | |
einval(). | |
@@ -3987,3 +4017,5 @@ nif_sockname(_Ref) -> | |
nif_peername(_Ref) -> | |
erlang:nif_error(undef). | |
+nif_ioctl(_SRef, _Req, _Args) -> | |
+ erlang:nif_error(undef). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SIOCGIFINDEX = 16#8933, | |
Dev = "enx0022cfab0ec2", | |
Body = list_to_binary([Dev, <<0:((15*8) - (length(Dev)*8)), 0:8, 0:128>>]), | |
{ok, Sock1} = socket:open(packet, raw, {raw, 16#300}), | |
{ok, Return} = socket:ioctl(Sock1, SIOCGIFINDEX, Body), | |
<<_Ifname:16/bytes, Ifr:32/native, _/binary>> = Return, | |
SockAddrLl = #{family => packet, protocol => 0, ifindex => Ifr, hatype => 0, pkttype => 0, halen => 0, addr => <<0:64>>}, | |
{ok, 0} = socket:bind(Sock1, SockAddrLl), | |
{ok, <<Dhost:6/bytes, Shost:6/bytes, Type:16, Payload/binary>>} = socket:recv(Sock1). |
Author
shun159
commented
Oct 8, 2019
こんにちは。Ethernet フレームを直接触りたいと思って困ってたら識者にここを教えてもらいました。
この patch、ご本家に Pull Request してもらうのはどうでしょうか。socket ライブラリで packet を扱えると大変ありがたいです。ご検討お願いします。
travelping/gen_socketをお使いください。申し訳ありませんが、私自身あまりErlangでEtherフレームを触るモチベーションがないのです…
ありがとうございます。無理をもうしてすみませんでした。
いえいえ
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment