Is it possible to return an address with Direct Request V2 Job Specs? - chainlink

Is it possible to return an address with Chainlink Direct Request V2 Job Specs?
I've noticed an ETH address is around 42 bytes so it won't fit into a bytes32 response type. I see the listed "Response Types" in the docs list:
uint256
int256
bool
bytes32 / bytes

You'd want to return a bytes32 and then convert it to an address.
From the solidity docs:
If you convert a type that uses a larger byte size to an address, for example bytes32, then the address is truncated. To reduce conversion ambiguity version 0.4.24 and higher of the compiler force you make the truncation explicit in the conversion. Take for example the 32-byte value 0x111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFFCCCC.
You can use address(uint160(bytes20(b))), which results in 0x111122223333444455556666777788889999aAaa, or you can use address(uint160(uint256(b))), which results in 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc.
Also see this related question.

Related

SOCKADDR_INET in golang

I have a byte array that is actually filled with SOCKADDR_INET structures by C++ function in the kernel, after transfer to user mode I need to marshal it in the slice of SOCKADDR_INET equivalent. The syscall package contains sockaddr_in and sockaddr_in6 but as I see golang has a lack of a union to emulate SOCKADDR_INET. I'm new in golang so wondering about the right solution for this case.
The si_family field at the end identifies if the bytes should be interpreted as IPv4 or IPv6 SOCKADDR structure.
The most easy route is likey to make a function to unmarshall the bytes into a go version of the SOCKADDR_IN or SOCKADDR_IN6 struct depending on the value of si_family.

How to send multipart messages using libnl and generic netlink?

I'm trying to send a relatively big string (6Kb) through libnl and generic netlink, however, I'm receiving the error -5 (NL_ENOMEM) from the function nla_put_string in this process. I've made a lot of research but I didn't find any information about these two questions:
What's the maximum string size supported by generic netlink and libnl nla_put_string function?
How to use the multipart mechanism of generic netlink to broke this string in smaller parts to send and reassemble it on the Kernel side?
If there is a place to study such subject I appreciate that.
How to use the multipart mechanism of generic netlink to broke this string in smaller parts to send and reassemble it on the Kernel side?
Netlink's Multipart feature "might" help you transmit an already fragmented string, but it won't help you with the actual string fragmentation operation. That's your job. Multipart is a means to transmit several small correlated objects through several packets, not one big object. In general, Netlink as a whole is designed with the assumption that any atomic piece of data you want to send will fit in a single packet. I would agree with the notion that 6Kbs worth of string is a bit of an oddball.
In actuality, Multipart is a rather ill-defined gimmic in my opinion. The problem is that the kernel doesn't actually handle it in any generic capacity; if you look at all the NLMSG_DONE usage instances, you will notice not only that it is very rarely read (most of them are writes), but also, it's not the Netlink code but rather some specific protocol doing it for some static (ie. private) operation. In other words, the semantics of NLMSG_DONE are given by you, not by the kernel. Linux will not save you any work if you choose to use it.
On the other hand, libnl-genl-3 does appear to perform some automatic juggling with the Multipart flags (NLMSG_DONE and NLM_F_MULTI), but that only applies when you're sending something from Kernelspace to Userspace, and on top of that, even the library itself admits that it doesn't really work.
Also, NLMSG_DONE is supposed to be placed in the "type" Netlink header field, not in the "flags" field. This is baffling to me, because Generic Netlink stores the family identifier in type, so it doesn't look like there's a way to simultaneously tell Netlink that the message belongs to you, AND that it's supposed to end some data stream. Unless I'm missing something important, Multipart and Generic Netlink are incompatible with each other.
I would therefore recommend implementing your own message control if necessary and forget about Multipart.
What's the maximum string size supported by generic netlink and libnl nla_put_string function?
It's not a constant. nlmsg_alloc() reserves
getpagesize() bytes per packet by default. You can tweak this default with nlmsg_set_default_size(), or more to the point you can override it with nlmsg_alloc_size().
Then you'd have to query the actual allocated size (because it's not guaranteed to be what you requested) and build from there. To get the available payload you'd have to subtract the Netlink header length, the Generic Header length and the Attribute Header lengths for any attributes you want to add. Also the user header length, if you have one. You would also have to align all these components because their sizeof is not necessarily their actual size (example).
All that said, the kernel will still reject packets which exceed the page size, so even if you specify a custom size you will still need to fragment your string.
So really, just forget all of the above. Just fragment the string to something like getpagesize() / 2 or whatever, and send it in separate chunks.
This is the general idea:
static void do_request(struct nl_sock *sk, int fam, char const *string)
{
struct nl_msg *msg;
msg = nlmsg_alloc();
genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, fam,
0, 0, DOC_EXMPL_C_ECHO, 1);
nla_put_string(msg, DOC_EXMPL_A_MSG, string);
nl_send_auto(sk, msg);
nlmsg_free(msg);
}
int main(int argc, char **argv)
{
struct nl_sock *sk;
int fam;
sk = nl_socket_alloc();
genl_connect(sk);
fam = genl_ctrl_resolve(sk, FAMILY_NAME);
do_request(sk, fam, "I'm sending a string.");
do_request(sk, fam, "Let's pretend I'm biiiiiig.");
do_request(sk, fam, "Look at me, I'm so big.");
do_request(sk, fam, "But I'm already fragmented, so it's ok.");
nl_close(sk);
nl_socket_free(sk);
return 0;
}
I left a full sandbox in my Dropbox. See the README. (Tested in kernel 5.4.0-37-generic.)

What is the most efficient protobuf type (in C++) for storing ipv4 or ipv6 address? My address is a boost::asio::ip::address_v4 (or v6)

I read that protobuf has a type called "bytes" which can store arbitrary number of bytes and is the equivalent of "C++ string". The reason why I don't prefer to use "bytes" is that it expects input as a C++ string i.e., boost IP will need to be converted to a string. Now my concern lies here : I want to perform serialize and send the encoded protobuf message over TCP socket. I want to ensure that the encoded message size is as small as possible.
Currently, I am using the below .proto file :
syntax = "proto2";
message profile
{
repeated **uint32** localEndpoint = 1;
repeated **uint32** remoteEndpoint = 2;
}
In order to save boost IP in the protobuf message, I am first converting boost IP into byte-format array by using "boost::asio::ip::address_v4::to_bytes()". So for a v4 IP, resultant array size is 4. Then I am converting 1st 4 bytes from the resultant byte-array into one uint32_t number and then storing in "localEndpoint" field of the protobuf message. Likewise, I repeat for the next 4 bytes (for v6). I am taking 4 bytes at a time so as to utilize full 32 bits of the uint32.
Hence for a v4 address, 1 occurrence of "localEndpoint" field is used.
Similarly, for a v6 address, 4 occurrence of "localEndpoint" field is used.
Please allow me to highlight that if I had used "bytes" here, my input string itself would have been of size 15 bytes for a v4 ip like 111.111.111.111
Using uint32 instead of "bytes" does save me some encoded-data-size but I am looking for a more efficient protobuf type requiring lesser number of bytes.
Sorry for a long description but I wanted to explain my query in details. Please help me.. Thanks a lot in advance :)
An ipv4 address should require exactly 4 bytes. If you're somehow getting 8, you're doing something wrong - are you perhaps hex-encoding it? You don't need that here. Likewise, ipv6 should be 16 bytes.
4 bytes with a usually-set high byte is most effectively stored as fixed32 - varint would be overhead here, due to the high bits. 16 bytes is more subtle - I'd go with bytes (field header plus length), since it is simpler to form into a union, and if the field-number is large, it avoids having to pay for multiple multi-byte field headers (a length prefix of 16 will always be single-byte).
I'd then create a union of these via oneof:
oneof ip_addr {
fixed32 v4 = 1;
bytes v6 = 2;
}

What is the time frame used to collect data for oid 1.3.6.1.2.1.2.2.1.10(ifInOctets(10) )

When I do an snmpwalk for oid 1.3.6.1.2.1.2.2.1.10.1 I get a Counter32 integer value as the result. [1] states that 1.3.6.1.2.1.2.2.1.10 gives total number of octets received on the interface, including framing characters.
Does anybody knows for which time frame snmp gives this integer value because what I get is a pretty large value.
[1] http://www.oid-info.com/get/1.3.6.1.2.1.2.2.1.10
Thank you.
In RFC 202 you can find the mapping of MIB objects to their corresponding item in IEEE 802.12,
https://www.rfc-editor.org/rfc/rfc2020#page-12
That means, SNMP only exposes those values directly from the network adapters, without any processing at SNMP layer. Thus, when you see a value for ifInOctets, it is very likely to be an accumulated value since the last reset of this adapter (may or may not be related to device reset).

using int64 type for snmp v2c oid?

I am debugging some snmp code for an integer overflow problem. Basically we use an integer to store disk/raid capacity in KB. However when a disk/raid of more than 2TB is used, it'll overflow.
I read from some internet forums that snmp v2c support integer64 or unsigned64. In my test it'll still just send the lower 32 bits even though I have set the type to integer64 or unsigned64.
Here is how I did it:
a standalone program will obtain the capacity and write the data to a file. example lines for raid capacity
my-sub-oid
Counter64
7813857280
/etc/snmp/snmpd.conf has a clause to pass thru the oids:
pass_persist mymiboid /path/to/snmpagent
in the mysnmpagent source, read the oidmap into oid/type/value structure from the file, and print to stdout.
printf("%s\n", it->first.c_str());
printf("%s\n", it->second.type.c_str());
printf("%s\n", it->second.value.c_str());
fflush(stdout);
use snmpget to get the sub-oid, and it returns:
mysuboid = Counter32: 3518889984
I use tcpdump and the last segment of the value portion is:
41 0500 d1be 0000
41 should be the tag, 05 should be the length, and the value is only carrying the lower 32-bit of the capacity. (note 7813857280 is 0x1.d1.be.00.00)
I do find that using string type would send correct value (in octetstring format). But I want to know if there is a way to use 64-bit integer in snmp v2c.
I am running NET-SNMP 5.4.2.1 though.
thanks a lot.
Update:
Found the following from snmpd.conf regarding pass (and probably also pass_persist) in net-snmp doc page. I guess it's forcing the Counter64 to Counter32.
Note:
The SMIv2 type counter64 and SNMPv2 noSuchObject exception are not supported.
You are supposed to use two Unsigned32 for lower and upper bytes of your large number.
Counter64 is not meant to be used for large numbers this way.
For reference : 17 Common MIB Design Errors (last one)
SNMP SMIv2 defines a new type Counter64,
https://www.rfc-editor.org/rfc/rfc2578#page-24
which is in fact unsigned 64 bit integer. So if your data fall into the range, using Counter64 is proper.
"In my test it'll still just send the lower 32 bits even though I have set the type to integer64 or unsigned64" sounds like a problem, but unless you show more details (like showing some code) on how you tested it out and received the result, nobody might help further.

Resources