TFTP packet example? - ruby

I'm writing a TFTP server in Ruby and I don't understand a couple things.
First, I read through the entire RFC and I understand the TFTP part of the packet (2 bytes opcode, etc), but I don't know where the TID's go. Also, I've never done anything in Ruby at a byte level. I don't know how to create a variable that's 2 bytes this and then 1 byte that and then whatever.
If someone could show me an example of how to construct a read request packet in ruby, that'd be sweet. Say I'm on the client side and I select port #20000 (for my local TID) and I want to read the file named /Users/pachun/documents/hello.txt on the server which has a TID of 69 right now because it's the first request. How would I construct that packet in Ruby?

Check out this project:
https://github.com/spiceworks/net-tftp
The code there should answer your questions regarding how to construct byte sequences for communicating with tftp protocol.

Related

Reveng to find out CRC algorithm in closed protocol

I have one machine with closed protocol and another device "gateway Modbus" from the same manufacter. This gateway convert this protocol to RS-485 Modbus.
When I send a command packet (modbus function 16) to gateway, gateway send (converted) specific packet to the machine and when I inject this packet over simple UART communication, machine can understand and change values too. I create a list with some cloned commands, but I need to know how CRC/checksum/etc is calculed (I think) to create custom packets.
I already used RevEng tool (https://reveng.sourceforge.io/) and CRCcalculator (https://crccalc.com/) trying to find some common crc algorithm with cloned packets, but none worked.
Some cloned packets, where 2 last bytes is CRC/etc. In this packets I changed the temperature value from 0x11 to 0x15 and last 2 bytes changed too (maybe crc/checksum/etc):
9A56F1FE0EB9001100000100641C
9A56F1FE0EB90012000001006720
9A56F1FE0EB90013000001006620
9A56F1FE0EB9001400000100611C
9A56F1FE0EB9001500000100601C
RevEng output:
./reveng -w 16 -l -s 9A56F1FE0EB9001100000100641C 9A56F1FE0EB90012000001006720 9A56F1FE0EB90013000001006620 9A56F1FE0EB9001400000100611C 9A56F1FE0EB9001500000100601C
./reveng: no models found
Someone can help me?
It's not a CRC. The second-to-last byte is the exclusive-or sum of the preceding bytes. I'm not sure what the last byte is, but since it is only taking on two different values in your example, it does not appear to be part of a check value. Or if it is, it's a rather ineffective check value algorithm.

Embarcadero RAD Studio & Indy. Error message “Package Size Too Big”

I use Embarcadero RAD Studio & Indy and I have a problem.
I am using component IdUDPServer and try to send file via UDP messages.
The file is successfully transferred if it is not large.
However, the error message “Package Size Too Big” appears if the file is large.
My code:
FileAPP->ReadBuffer(Buffer, Size);
IdUDPServer1->SendBuffer("10.6.1.255", 34004, RawToBytes(&Buffer, Size));
I see two ways to solve this problem:
1) Compose small messages and send these messages in a loop.
This is an easy way to solve the problem, however I will need to fix the remote application.
This is currently difficult. I do not have much time.
2)I want to find a condition in the source code where this error message is generated.
Maybe I can fix the condition and it will work for my specific task.
I have added some pictures. This is all the information that I now have.
Screenshots from help file: Picture 1, Picture 2, Picture 3
Error message: Picture 4
Please help me if you know the solution.
"Package Size Too Big" means you tried to send a datagram that is too large for UDP to handle. UDP has an effective max limit of 65507 bytes of payload data per datagram. You can't send a large file in a single datagram, it just won't fit.
So yes, you will have to break up your file into smaller chucks that are sent in separate datagrams. And as such, because UDP is connection-less and does not guarantee delivery, you will also have to solve the issues of lost packets and out-of-order packets. You will have to put a rolling sequence number inside your packets so that the receiver can save packets in the proper order. And you will have to implement a re-transmission mechanism to re-send lost packets that the receiver did not receive.
I would suggest not using TIdUDPClient/TIdUDPServer to implement file transfers manually, if possible. Indy has TIdTrivialFTP/TIdTrivialFTPServer components that implement the standardized UDP-based TFTP protocol, which handles these kind of details for you. By default, TFTP has a limit of ~32MB per file (512 bytes per datagram * 65535 datagrams max), but you can increase that limit using the TIdTrivialFTP.RequestedBlockSize property to request permission from a TFTP server to send more bytes per datagram. RequestedBlockSize is set to 1500 bytes by default, which can accommodate files up to ~93.7MB in size (though in practice it should not be set higher than 1468 bytes so TFTP datagrams won't exceed the MTU size of Ethernet packets, thus limiting the max file size closer to ~91.7MB). The RequestedBlockSize can be set as high as 65464 bytes per datagram to handle files up to ~3.9GB (at the risk of fragmenting UDP packets at the IP layer).
It is also possible for TFTP to handle unlimited file sizes with smaller datagram sizes, though TidTrivialFTP/TIdTrivialFTPServer do not currently implement this, because this behavior is not currently standardized in the TFTP protocol, but is commonly implemented as an extension in 3rd party implementations.
Otherwise, you should consider using TCP instead of UDP for your file transfers. TCP doesn't suffer from these problems.

Reading unterminated data with CocoaAsyncSocket's GCDAsyncSocket

I am trying to create an app that opens a listening TCP socket and then reads all bytes written to the socket and then does something with those bytes. The server does not know the length of the data that will be written to the socket. Also, there is not a terminating character in the data that is sent. What I would like to do is simply read all the available bytes, delay a short while, and try to read more bytes, etc. Is there an easy way to do this? I would like to just do something like read 100 bytes with a timeout or 1 second, then if the read timesout, get all the data that is available and then start reading again.

Formatting Modbus requests in ruby

I have a modbus device I am trying to communicate with using an ethernet to RS485 device. I'm not sure whether the device uses modbus ASCII or RTU.
I am trying to format a request to a device with address 1. The command code is 11h. I'm not sure I'm formatting the request properly
Here is the string I am using for ASCII - ":010B000000000C\x0D\x0A"
Here is the hex I'm using for RTU: "\x01\x0B\x00\x00\x00\x00\x0B\xA4"
When I send this command it is echoed back but I'm not getting responses. I've been through the modbus documentation and I think I have the correct byte structure. I'm wondering if I'm encoding it right for ruby?
It turned out my ethernet to RS485 device wasn't capable of the correct timing for modbus. Once I purchased a new unit the ascii strings worked.
Are you sure the checksum should be written in pure bytes, not in ASCII? I mean, try to send :010B000000000C0D0A instead of :010B000000000C\x0D\x0A.
Also, you wrote that the command is 11h - for my understanding it is 0x11 (hex), and you are sending 0x0B. Or the command is 11 (dec)?

ruby socket issue

i'm still kind of newbie to ruby, but i became used on using ruby sockets, cause i used the 'Socket' class many times, and so i having full control to my sockets and their options.
the thing is i'm trying to make it a little easy for me, so i'm trying to use the 'TCPSocket' class ,witch (i guess) doesn't give u much control as the 'Socket' class.
my script looks like this:
require 'socket'
client = TCPSocket.open('5.5.5.5', '5555')
client.send("msg", 0) # 0 means standard packet
client.close
the question is, what is suppose to be instead of the '0' on the send line ?? and if '0' means standard packet, what other than standard can exist there, is it some control over the TCP packet ?? if so, then it will be much easier for me than writing the whole socket by hand using the 'Socket' class.
The second parameter to send is the flags parameter. It gets passed onto the the send system call. You'll normally want to leave this at 0.
On my system, according to the man page, the other possible flags are:
#define MSG_OOB 0x1 /* process out-of-band data */
#define MSG_DONTROUTE 0x4 /* bypass routing, use direct interface */

Resources