Description
Scenario: Switching from a primary to a backup network, the firewall invalidates all existing tcp sessions and starts dropping packets.
Expected results: Configured timeout is hit and tiny_tds reports an error
Actual results: No response from tiny_tds until underlying tcp connection's retries expire (> 15 minutes on Ubuntu, for example: https://pracucci.com/linux-tcp-rto-min-max-and-tcp-retries2.html)
Simple sample code attached in timeout.zip file. You'll need to simulate dropped packets in order to see the issue, which is shown about halfway down the attached freetds.log. Freetds reports a timeout in the log, over and over and over, but tiny_tds does not return any error to the caller. I am not sure if the issue is actually with tiny_tds or freetds.
Steps to reproduce:
- Prereqs
- A firewall is required that can be configured to drop packets, in order to simulate the condition. iptables is sufficient (e.g. apt-get install iptables), or pfctl on Mac.
- Configure freetds to debug:
dump file = /tmp/freetds.log
debug flags = 0xffff
- Extract timeout.zip
- Modify main.rb for your database connection
- bundle install
- bundle exec ruby main.rb
- You'll need to complete step 6 while main.rb is running. Modify the loop as required.
- Interrupt the database connection:
- For linux:
iptables -I INPUT -s 1.2.3.4 -j DROP (where 1.2.3.4 is your db's ip address) - For mac:
- Append to /etc/pf.conf (or create a custom pf.conf):
block drop from 1.2.3.4 to any (where 1.2.3.4 is your db's ip address) - sudo pfctl /etc/pf.conf
- Append to /etc/pf.conf (or create a custom pf.conf):
- For linux:
At this point you should see the repeatedly ignored timeouts in freetds.log. On Linux this will continue for over 15 minutes before the connection finally times out. On Mac it takes around 30 seconds.
You can restore your connection by replacing DROP with ACCEPT for iptables, or by removing the extra line from pf.conf and running pfctl again.