newspaint

Documenting Problems That Were Difficult To Find The Answer To

Wireshark Showing Wrong Timezone/Times for Packets

If you find yourself wondering why Wireshark seems to be displaying the wrong time for packets – it could be something as simple as having configured the display timezone incorrectly.

If the timestamps appear to be for the wrong timezone...

If the timestamps appear to be for the wrong timezone…

 

Right click the column header “Time” and choose Column Preferences…

Right click on the Time column header and choose Column Preferences...

Right click on the Time column header and choose Column Preferences…

 

Next double click (using left mouse button) on the “Type” field to bring up a drop down list of options.

Double click on the Type field for the Time row

Double click on the Type field for the Time row

 

From the drop down list choose “Time (format as specified)”. If this was set to something different (e.g. “UTC time”) then this could explain why you saw a different date/time in the packet capture display.

Choose "Time (format as specified)" from the drop down list

Choose “Time (format as specified)” from the drop down list

Introduction to Packet Capture on Microsoft Windows for Later Analysis with Wireshark

Windows versions 7 and above come with the netsh trace command which can be used to take packet captures – however these captures are incompatible with Wireshark. Such captures can be converted into a basic format that can be read with Wireshark using the Microsoft Message Analyzer that Microsoft makes freely available (a 68MB download).

The process is typically:

  • netsh trace show – get information useful to use when specifying the trace
  • netsh trace start – begin a trace specifying filters to use
  • netsh trace stop – end the trace and create the capture file

You can get information for the netsh trace show command:

C:\> netsh trace show /?

The following commands are available:

Commands in this context:
show CaptureFilterHelp - List supported capture filters and usage.
show globalKeywordsAndLevels - List global keywords and levels.
show helperclass - Show helper class information.
show interfaces - List available interfaces.
show provider  - Shows provider information.
show providers - Shows available providers.
show scenario  - Shows scenario information.
show scenarios - Shows available scenarios.
show status    - Shows tracing configuration.

The most useful of these is netsh trace show CaptureFilterHelp as follows:

  Capture Filters:
        Capture filters are only supported when capture is explicitly
        enabled with capture=yes. Supported capture filters are:

        CaptureInterface=<interface name or GUID>
         Enables packet capture for the specified interface name or GUID. Use
         'netsh trace show interfaces' to list available interfaces.
        e.g. CaptureInterface={716A7812-4AEE-4545-9D00-C10EFD223551}
        e.g. CaptureInterface=!{716A7812-4AEE-4545-9D00-C10EFD223551}
        e.g. CaptureInterface="Local Area Connection"

        Ethernet.Address=<MAC address>
         Matches the specified filter against both source and destination
         MAC addresses.
        e.g. Ethernet.Address=00-0D-56-1F-73-64

        Ethernet.SourceAddress=<MAC address>
         Matches the specified filter against source MAC addresses.
        e.g. Ethernet.SourceAddress=00-0D-56-1F-73-64

        Ethernet.DestinationAddress=<MAC address>
         Matches the specified filter against destination MAC addresses.
        e.g. Ethernet.DestinationAddress=00-0D-56-1F-73-64

        Ethernet.Type=<ethertype>
         Matches the specified filter against the MAC ethertype.
        e.g. Ethernet.Type=IPv4
        e.g. Ethernet.Type=NOT(0x86DD)
        e.g. Ethernet.Type=(IPv4,IPv6)

        Wifi.Type=<Management|Data>
         Matches the specified filter against the Wifi type. Allowed values
         are 'Management' and 'Data'. If not specified, the Wifi.Type filter
         is not applied.
         Note: This capture filter does not support ranges, lists or negation.
        e.g. Wifi.Type=Management

        Protocol=<protocol>
         Matches the specified filter against the IP protocol.
        e.g. Protocol=6
        e.g. Protocol=!(TCP,UDP)
        e.g. Protocol=(4-10)

        IPv4.Address=<IPv4 address>
         Matches the specified filter against both source and destination
         IPv4 addresses.
        e.g. IPv4.Address=157.59.136.1
        e.g. IPv4.Address=!(157.59.136.1)
        e.g. IPv4.Address=(157.59.136.1,157.59.136.11)

        IPv4.SourceAddress=<IPv4 address>
         Matches the specified filter against source IPv4 addresses.
        e.g. IPv4.SourceAddress=157.59.136.1

        IPv4.DestinationAddress=<IPv4 address>
         Matches the specified filter against destination IPv4 addresses.
        e.g. IPv4.DestinationAddress=157.59.136.1

        IPv6.Address=<IPv6 address>
         Matches the specified filter against both source and destination
         IPv6 addresses.
        e.g. IPv6.Address=fe80::5038:3c4:35de:f4c3\%8
        e.g. IPv6.Address=!(fe80::5038:3c4:35de:f4c3\%8)

        IPv6.SourceAddress=<IPv6 address>
         Matches the specified filter against source IPv6 addresses.
        e.g. IPv6.SourceAddress=fe80::5038:3c4:35de:f4c3\%8

        IPv6.DestinationAddress=<IPv6 address>
         Matches the specified filter against destination IPv6 addresses.
        e.g. IPv6.DestinationAddress=fe80::5038:3c4:35de:f4c3\%8

        CustomMac=<type(offset,value)>
         Matches the specified filter against the value at the specified
         offset starting with the MAC header.
         Note: This capture filter does not support ranges, lists or negation.
        e.g. CustomMac=UINT8(0x1,0x23)
        e.g. CustomMac=ASCIISTRING(3,test)
        e.g. CustomMac=UNICODESTRING(2,test)

        CustomIp=<type(offset,value)>
         Matches the specified filter against the value at the specified
         offset starting with the IP header.
         Note: This capture filter does not support ranges, lists or negation.
        e.g. CustomIp=UINT16(4,0x3201)
        e.g. CustomIp=UINT32(0x2,18932)

        CaptureMultiLayer=<yes|no>
         Enables multi-layer packet capture.
         Note: This capture filter does not support ranges, lists or negation.

        PacketTruncateBytes=<value>
         Captures only the the specified number of bytes of each packet.
         Note: This capture filter does not support ranges, lists or negation.
        e.g. PacketTruncateBytes=40

Note:
        Multiple filters may be used together. However the same filter may
        not be repeated.
        e.g. 'netsh trace start capture=yes Ethernet.Type=IPv4
              IPv4.Address=157.59.136.1'

        Filters need to be explicitly stated when required. If a filter is
        not specified, it is treated as "don't-care".
         e.g. 'netsh trace start capture=yes IPv4.SourceAddress=157.59.136.1'
              This will capture IPv4 packets only from 157.59.136.1, and it
              will also capture packets with non-IPv4 Ethernet Types, since
              the Ethernet.Type filter is not explicitly specified.
         e.g. 'netsh trace start capture=yes IPv4.SourceAddress=157.59.136.1
               Ethernet.Type=IPv4'
              This will capture IPv4 packets only from 157.59.136.1. Packets
              with other Ethernet Types will be discarded since an explicit
              filter has been specified.

        Capture filters support ranges, lists and negation (unless stated
        otherwise).
         e.g. Range: 'netsh trace start capture=yes Ethernet.Type=IPv4
                      Protocol=(4-10)'
              This will capture IPv4 packets with protocols between 4 and 10
              inclusive.
         e.g. List: 'netsh trace start capture=yes Ethernet.Type=(IPv4,IPv6)'
              This will capture only IPv4 and IPv6 packets.
         e.g. Negation: 'netsh trace start capture=yes Ethernet.Type=!IPv4'
              This will capture all non-IPv4 packets.

        Negation may be combined with lists in some cases.
         e.g. 'netsh trace start capture=yes Ethernet.Type=!(IPv4,IPv6)'
               This will capture all non-IPv4 and non-IPv6 packets.

        'NOT' can be used instead of '!' to indicate negation. This requires
        parentheses to be present around the values to be negated.
         e.g. 'netsh trace start capture=yes Ethernet.Type=NOT(IPv4)'

You can get information about the netsh trace start command:

C:\> netsh trace start /?

start
  Starts tracing.

  Usage: trace start [[scenario=]]
        [[globalKeywords=]keywords] [[globalLevel=]level]
        [[capture=]yes|no] [[report=]yes|no]
        [[persistent=]yes|no] [[traceFile=]path\filename]
        [[maxSize=]filemaxsize] [[fileMode=]single|circular|append]
        [[overwrite=]yes|no] [[correlation=]yes|no|disabled] [capturefilters]
        [[provider=]providerIdOrName] [[keywords=]keywordMaskOrSet]
        [[level=]level] [[provider=]provider2IdOrName]
        [[keywords=]keyword2MaskOrSet] [[level=]level2] ...

Defaults:
        capture=no (specifies whether packet capture is enabled
                in addition to trace events)
        report=no (specifies whether a complementing report will be generated
                along with the trace file)
        persistent=no (specifies whether the tracing session continues
                across reboots, and is on until netsh trace stop is issued)
        maxSize=250 MB (specifies the maximum trace file size, 0=no maximum)
        fileMode=circular
        overwrite=yes (specifies whether an existing trace output file will
                be overwritten)
        correlation=yes (specifies whether related events will be correlated
                and grouped together)
        traceFile=%LOCALAPPDATA%\Temp\NetTraces\NetTrace.etl
                (specifies location of the output file)

Provider keywords default to all and level to 255 unless otherwise specified.

For example:

netsh trace start scenario=InternetClient capture=yes

        Starts tracing for the InternetClient scenario and dependent providers
                with packet capture enabled.
        Tracing will stop when the "netsh trace stop" command is issued
                or when the system reboots.
        Default location and name will be used for the output file. If an old
                file exists, it will be overwritten.

netsh trace start provider=microsoft-windows-wlan-autoconfig
        keywords=state,ut:authentication

        Starts tracing for the microsoft-windows-wlan-autoconfig provider
        Tracing will stop when the "netsh trace stop" command is issued
                or when the system reboots.
        Default location and name will be used for the output file. If an old
                file exists, it will be overwritten.
        Only events with keyword 'state' or 'ut:authentication' will be logged.

        netsh trace show provider command can be used to display
                supported keywords and levels.

Capture Filters:
        Capture filters are only supported when capture is explicitly
        enabled with capture=yes. Use 'netsh trace show CaptureFilterHelp'
        to display a list of supported capture filters and their usage.

All captures should, unless you have a more specific goal in mind, have the Capture=yes parameter at the beginning of the trace statement, and provider=Microsoft-Windows-NDIS-PacketCapture level=5 keywords=ut:ReceivePath,ut:SendPath provider=Microsoft-Windows-Networking-Correlation level=1 keywords=ut:Packet at the end of the trace statement (after the capture filters have been specified) to ensure just the packet data is captured and not other verbose unrelated messages.

Optionally choose an interface:

C:\> netsh trace show interface
Ethernet adapter Local Area Connection 4:
    Description:     Intel(R) PRO/1000 MT Desktop Adapter
    Interface GUID:  {7C101C48-7750-4876-9746-C55584C59818}
    Interface Index: 21
    Interface Luid:  0x6000011000000

Ethernet adapter VirtualBox Host-Only Network:
    Description:     VirtualBox Host-Only Ethernet Adapter
    Interface GUID:  {2557E211-2DEF-47E6-B6B6-B56CD20092D5}
    Interface Index: 17
    Interface Luid:  0x600000F000000

Some examples:

Command Description
netsh trace start Capture=yes Correlation=no Report=no Scenario=InternetClient Tracefile=c:\temp\capture.etl Ethernet.Type=IPv4 IPv4.Address=(10.0.0.1,10.1.0.1,10.2.0.1,10.3.0.1) Protocol=UDP PacketTruncateBytes=256 CaptureInterface={7C101C48-7750-4876-9746-C55584C59818} limit packet captures to first 256 bytes of each packet, UDP only, IPv4 only, on the network interface specified only, to the specified etl file, make no report, do not correlate, and to/from any of the 4 IP addresses specified
netsh trace start Capture=yes Correlation=no Report=no Tracefile=c:\temp\capture.etl Ethernet.Type=IPv4 IPv4.Address=(10.0.0.1,10.1.0.1,10.2.0.1,10.3.0.1) Protocol=UDP PacketTruncateBytes=256 CaptureInterface={7C101C48-7750-4876-9746-C55584C59818} provider=Microsoft-Windows-NDIS-PacketCapture level=5 keywords=ut:ReceivePath,ut:SendPath provider=Microsoft-Windows-Networking-Correlation level=1 keywords=ut:Packet largely prevent “Microsoft_Windows_Networking_Correlation” module noise in packet capture by limiting verbosity level to 1, specify that packets coming in and going out should be captured with debugging level (5) verbosity for the “Microsoft-Windows-NDIS-PacketCapture” provider, everything else as above (produces far smaller capture files, note that the provider specifications should come after the filters)

Converting to Wireshark .cap Format: you can either use the Microsoft Message Analyzer GUI to open the .etl file, wait until it has processed the entire file (takes tens of minutes), and then save the file as a .cap export.

Or you can do the following in Powershell:

import-module PEF
$s = New-PefTraceSession -Path "C:\temp\wireshark-dump.cap" -SaveOnStop
$s | Add-PefMessageProvider -Provider "C:\temp\capture.etl"
$s | Start-PefTraceSession

So what can’t netsh do?

  • capture a specific application protocol, such as DNS, SNMP, or the like, because it does not permit matching on ports, and even if you tried using CustomIp=UINT16(22,53) you have to hope that the IPv4 header is its minimum 20 bytes and no longer and you can only capture on source OR destination ports but not both which means you will not see request/response pairs which is so essential to any tracing session
  • export in a Wireshark-friendly format

The provided “netsh trace” command that comes with Microsoft products is conclusive proof that Windows is never a good solution in an enterprise environment. While Linux servers have the “tcpdump” tool that allows specific filtering on so many different parameters the Windows “netsh trace” command flails around unable to be of much use to anybody trying to debug a networking or application related issue.

Any time a “Solution Architect” recommends a Windows or other Microsoft related product you will know instantly that they have never had to maintain or troubleshoot a real enterprise system in the wild.

Splunk Regular Expression Flags

Very little is openly documented about Splunk regular expressions – which is surprising given how important pattern matching is when trawling through large amounts of data.

Most documentation about Splunk regular expressions is found at this linked page.

In addition the two most commonly used functions that utilise regular expressions during searches are:

  • regex – filters based on regular expression, i.e. matches or doesn’t match (if field!=regex syntax is used)
  • rex – allows extraction of named capturing groups from text into parameters, does not filter

Flags

The hint about supported flags comes from the documentation of the regex command which states:

The regular expression must be a Perl Compatible Regular Expression supported by the PCRE library.

Possible flags are described in PHP’s PCRE pattern modifiers page however not all apply to Splunk.

Here are the flags that appear supported in Splunk:

Modifier Behaviour Example Matches When Used
(?i) case insensitive (?i)moon Moon
(?m) ^ and $ can match beginning and end of line as well as string (?m)^The Who art thou?
The butler.
(?s) dot matches newlines (?s)P.G It is P
G.
(?x) extended, white space in expression is ignored (?x)ID \d+ ID4132
(?U) ungreedy, by default make expressions ungreedy, and greedy if question mark used (?U)(M.+t) Meet the president

Citrix Keyboard Shortcuts for Linux Receiver

From this page:

Combination Description
SHIFT+F1 Displays the Windows Task List
SHIFT+F2 Displays or Hides the Windows Title Bar for the Citrix Receiver Client window
SHIFT+F3 Disconnects the ICA session and exits the Citrix Receiver
CTRL+F1 Opens the Windows Security dialog box (similar to CTRL+ALT+DEL)
CTRL+F2 Displays the remote computer’s Start Menu (similar to CTRL+ESC)
CTRL+F3 Displays the Windows Task Manager (similar to CTRL+SHIFT+ESC)
ALT+F2 Cycles through running programs in the Citrix session (similar to ALT+ESC)
ALT+PLUS Switches between programs from left to right (similar to ALT+TAB)
ALT+MINUS Switches between programs from right to left (similar to ALT+SHIFT+TAB)

Building OpenTTD on Debian 9 Stretch amd64

Note the instructions at the OpenTTD development page.

Get the source repository using Git (from repository):

apt-get install git
git clone http://git.openttd.org/tags/1.7.2.git

Get basic build tools:

apt-get install binutils gcc g++ make pkg-config

Get the library dependencies:

apt-get install zlib1g-dev liblzma-dev liblzo2-dev libpng-dev libfreetype6-dev libfontconfig1-dev libsdl1.2-dev libicu-dev

Configure:

./configure --prefix-dir=/opt/openttd

Build:

nice make -j 2

Install:

nice make install

Want to run it inside a LXC container with X Windows and audio? See this article.

Visual Basic Macro to Change Selected Text to Courier New 9pt

Before any macros can be created in Microsoft Office 2010 and later (with the utterly ridiculous, dysfunctional, and pointless “ribbon” interface – seriously, Microsoft couldn’t get anything more wrong than removing menus from applications the world had come to depend upon) a “developer” toolbar has to be enabled.

  • choose the File toolbar from the utterly ridiculous and dysfunctional ribbon
  • on the left hand side choose “Options” – this will bring up a dialog box of options
  • choose the awfully and ignorantly spelt Americanised option “Customize Ribbon”
  • on the right hand ride where it says, in ridiculous American spelling, “Customize the Ribbon”, check the “Developer” Main Tab, then click OK on the dialog box

Now macros can be created by choosing the “Developer” toolbar from the utterly ridiculous and dysfunctional ribbon, and the “Macros” button can be clicked from there.

A macro name can be given, such as “selection_to_fixed_width“, with the following code (thanks to this post for guidance):

Sub selection_to_fixed_width()
  Dim oInspector As Inspector
  Dim oSelection
  Dim iRet As Integer
   
  Set oInspector = Application.ActiveInspector
   
  If oInspector.EditorType = olEditorWord Then
    Dim oApplication
       
    Set oApplication = oInspector.WordEditor.Application
    Set oSelection = oApplication.Selection
  End If

  If oSelection Is Nothing Then
    iRet = MsgBox("Script does not know how to find a selection",vbOKOnly,"Error")
    Exit Sub
  End If
  
  Dim nLength As Integer
  nLength = oSelection.End - oSelection.Start
  
  If nLength < 1 Then
    iRet = MsgBox("No text selected", vbOKOnly, "Error")
    Exit Sub
  End If

  With oSelection
    .Font.Name = "Courier New"
    .Font.Size = 9
  End With
End Sub

You can now add a small button to your “quick access toolbar” which is the thin strip at the very top of every window (above the window’s title). Where you see a small drop down arrow with a horizontal line above it – click this upside-down looking eject icon. From the menu choose “More Commands…” – this opens a dialog box. In the “Choose commands from:” dropdown select Macros – then drag your macro from the left-hand list to the right-hand list titled “Customize Quick Access Toolbar”. Click OK and you now have an icon you can press to run the macro.

If this is Microsoft Outlook you’ll only want to do this on a “new message” window (as you’re only wanting to change text you’re writing/creating).

At some point you’ll restart your Microsoft Office application and find your macro no longer does anything. This is because Microsoft Office products, by default, disable macros from running. To enable them visit your Developer ribbon toolbar, click on “Macro Security”, and choose “Notifications for all macros” from the dialog box. Then click OK and restart your Microsoft Office application.

The next time you try and run your macro you should get a warning that macros are disabled and you should be asked whether you want to enable macros.

ZTE Axon 7 LineageOS 14.1 Terminal Permission Denied

You’ve rooted your A2017G ZTE Axon 7 and put LineageOS 14.1 on. You’ve also installed, through TWRP, the addonsu-14.1-arm64-signed.zip package from LineageOS 14.1 extras (because the device is of arm64 architecture).

So when you install Terminal Emulator (jackpal.androidterm) from Google Play and start it up you’re puzzled when you get the message “Permission denied” when you try and do anything:

axon7:/ $ ls
ls: .: Permission denied
1|axon7:/ $

The solution is to run /system/bin/su from the command line – then allow Terminal Emulator su (super user) privileges when a dialog pops up as a result.

axon7:/ $ /system/bin/su
axon7:/ #

From now on, when you start a Terminal Emulator session, you need to just type su at the beginning of each session.

axon7:/ $ su
axon7:/ #

What Processes Are Using Swap Memory in Linux?

On both RedHat 6 and Ubuntu Xenial the amount of a process’s memory stored in the swapfile can be found in the /proc/pid/status file for that process.

Such a file might contain the following (with many lines omitted for the sake of simplicity):

Name:   evolution-calen
State:  S (sleeping)
Tgid:   4207
Ngid:   0
Pid:    4207
PPid:   3688
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
VmPeak:   861644 kB
VmSize:   861500 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:     55848 kB
VmRSS:         0 kB
VmData:   477660 kB
VmStk:       132 kB
VmExe:         8 kB
VmLib:     80684 kB
VmPTE:       776 kB
VmPMD:        16 kB
VmSwap:    40128 kB
Threads:        5
voluntary_ctxt_switches:        439
nonvoluntary_ctxt_switches:     4

A Perl script can be used to list what processes currently have memory allocated in the swapfile:

#!/usr/bin/perl -w

use strict;

sub commify {
  local $_  = shift;
  1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
  return $_;
}

my %pids;

foreach my $fname ( glob( "/proc/*/status" ) ) {
  # slurp in status file for process
  local $/ = undef;
  my $fin;
  next if ( ! open( $fin, "<", $fname ) );
  my $data = <$fin>;
  close( $fin );

  # get PID
  next if ( $data !~ m/^Pid:\s*(\d+)/m );
  my $pid = $1;

  # get name
  next if ( $data !~ m/^Name:\s*(.*\S)/m );
  my $name = $1;

  # get swap
  next if ( $data !~ m/^VmSwap:\s*(\d+)\s*([a-zA-Z])?B/m );
  my $vmswap = $1;
  if ( $1 and ( lc($2) eq "k" ) ) {
    $vmswap *= 1024;
  } elsif ( $1 and ( lc($2) eq "m" ) ) {
    $vmswap *= 1024 * 1024;
  } elsif ( $1 and ( lc($2) eq "g" ) ) {
    $vmswap *= 1024 * 1024 * 1024;
  }

  $pids{$pid} = { 'name' => $name, 'vmswap' => $vmswap };
}

# list processes in order of swap memory usage
printf( "%-8s | %-19s | %-24s\n", "PID", "Swap Bytes", "Name" );
foreach my $pid ( sort { $pids{$b}->{'vmswap'} <=> $pids{$a}->{'vmswap'} } keys %pids ) {
  last if ( $pids{$pid}->{'vmswap'} == 0 );

  printf(
    "%8s | %19s | %-24s\n",
    $pid,
    commify( $pids{$pid}->{'vmswap'} ),
    substr( $pids{$pid}->{'name'}, 0, 24 )
  );
}

Typical output might be similar to:

PID      | Swap Bytes          | Name                    
    4207 |          41,091,072 | evolution-calen         
    4277 |          39,084,032 | evolution-calen         
    4288 |          36,646,912 | evolution-calen         
    2588 |          36,634,624 | Xorg                    
   21438 |          28,733,440 | thunderbird             
    4152 |          21,938,176 | blueman-applet          
    4120 |          10,338,304 | applet.py               
    3920 |           8,720,384 | Thunar                  
   10419 |           8,544,256 | gvfsd-http              
    3844 |           6,307,840 | gvfsd-fuse      

Cron – Authentication Failure

You’ve manually added a new user, possibly directly editing the /etc/passwd file, but getting the following errors in /var/log/syslog about cron:

Dec 30 20:57:01 myhost cron[61]: Authentication failure
Dec 30 20:57:01 myhost CRON[212]: Authentication failure

In my case it was because I failed to add a corresponding entry for the user in the /etc/shadow file.

Speeding Up ddrescue Kernel Timeouts on Bad Blocks on Ubuntu 16.04

I was having trouble recovering data from an old hard drive. But the worst part was that ddrescue appeared to freeze for 3 minutes trying to access a bad block.

I would see messages like the following in /var/log/syslog:

Sep 17 14:13:25 localhost kernel: [607885.497842] INFO: task ddrescue:14310 blocked for more than 120 seconds.
Sep 17 14:13:25 localhost kernel: [607885.497845]       Tainted: P           OE   4.4.0-93-generic #116-Ubuntu
Sep 17 14:13:25 localhost kernel: [607885.497845] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Sep 17 14:13:25 localhost kernel: [607885.497847] ddrescue        D ffff8802850db9e8     0 14310  14309 0x00000004
Sep 17 14:13:25 localhost kernel: [607885.497849]  ffff8802850db9e8 ffff8802850dba10 ffff8807f9f4aa00 ffff8807c0fdb800
Sep 17 14:13:25 localhost kernel: [607885.497851]  ffff8802850dc000 ffff88081dd96e00 7fffffffffffffff ffff880710370c00
Sep 17 14:13:25 localhost kernel: [607885.497852]  ffff8800d8972300 ffff8802850dba00 ffffffff8183f0d5 0000000000000000
Sep 17 14:13:25 localhost kernel: [607885.497853] Call Trace:
Sep 17 14:13:25 localhost kernel: [607885.497859]  [] schedule+0x35/0x80
Sep 17 14:13:25 localhost kernel: [607885.497861]  [] schedule_timeout+0x1b5/0x270
Sep 17 14:13:25 localhost kernel: [607885.497864]  [] ? __blk_run_queue+0x33/0x40
Sep 17 14:13:25 localhost kernel: [607885.497866]  [] ? queue_unplugged+0x2a/0xb0
Sep 17 14:13:25 localhost kernel: [607885.497867]  [] io_schedule_timeout+0xa4/0x110
Sep 17 14:13:25 localhost kernel: [607885.497870]  [] do_blockdev_direct_IO+0x19e2/0x3410
Sep 17 14:13:25 localhost kernel: [607885.497872]  [] ? I_BDEV+0x20/0x20
Sep 17 14:13:25 localhost kernel: [607885.497874]  [] __blockdev_direct_IO+0x43/0x50
Sep 17 14:13:25 localhost kernel: [607885.497875]  [] blkdev_direct_IO+0x58/0x80
Sep 17 14:13:25 localhost kernel: [607885.497877]  [] generic_file_read_iter+0x4e0/0x670
Sep 17 14:13:25 localhost kernel: [607885.497879]  [] ? fsnotify+0x307/0x4a0
Sep 17 14:13:25 localhost kernel: [607885.497880]  [] blkdev_read_iter+0x35/0x40
Sep 17 14:13:25 localhost kernel: [607885.497883]  [] new_sync_read+0x94/0xd0
Sep 17 14:13:25 localhost kernel: [607885.497885]  [] __vfs_read+0x26/0x40
Sep 17 14:13:25 localhost kernel: [607885.497886]  [] vfs_read+0x86/0x130
Sep 17 14:13:25 localhost kernel: [607885.497888]  [] SyS_read+0x55/0xc0
Sep 17 14:13:25 localhost kernel: [607885.497890]  [] entry_SYSCALL_64_fastpath+0x16/0x71
Sep 17 14:13:53 localhost kernel: [607913.902354] sd 38:0:0:0: timing out command, waited 180s
Sep 17 14:13:53 localhost kernel: [607913.902361] sd 38:0:0:0: [sdf] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
Sep 17 14:13:53 localhost kernel: [607913.902362] sd 38:0:0:0: [sdf] tag#0 Sense Key : Hardware Error [current] 
Sep 17 14:13:53 localhost kernel: [607913.902364] sd 38:0:0:0: [sdf] tag#0 Add. Sense: Logical unit communication CRC error (Ultra-DMA/32)
Sep 17 14:13:53 localhost kernel: [607913.902366] sd 38:0:0:0: [sdf] tag#0 CDB: Read(10) 28 00 07 bf 7b 00 00 00 80 00
Sep 17 14:13:53 localhost kernel: [607913.902367] blk_update_request: I/O error, dev sdf, sector 129989376

Clearly waiting 3 minutes for every bad block was unacceptable – especially given the possible extra damage being done to the hard drive.

The article at this link and the article at this link had a solution:

~# cat /sys/block/sdf/device/eh_timeout
10
~# cat /sys/block/sdf/device/timeout
30

~# echo -n "2" >/sys/block/sdf/device/eh_timeout
~# echo -n "3" >/sys/block/sdf/device/timeout

~# ddrescue -n -d -r1 /dev/sdf image-sdf-80G.bin image-sdf-80G.map
GNU ddrescue 1.19
Press Ctrl-C to interrupt
Initial status (read from logfile)
rescued:    24643 MB,  errsize:  23029 kB,  errors:     398

Current status
rescued:    80025 MB,  errsize:   79872 B,  current rate:        0 B/s
   ipos:    20015 MB,   errors:      32,    average rate:    9196 kB/s
   opos:    20015 MB, run time:    1.67 h,  successful read:      42 s ago
Retrying bad sectors... Retry 1 (forwards)

This greatly reduced the time before ddrescue gave up on a block to several seconds (~20 seconds) from several minutes.

How to Mount Partition from Disk Image

Adopted from this article.

First identify the starting offset of the partition you want to mount. To do this use the parted print command to list the partitions:

~$ parted image-sdf-80G.bin unit B print
Model:  (file)
Disk /tmp/image-sdf-80G.bin: 80025280000B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start         End           Size          Type      File system  Flags
 1      32256B        2146798079B   2146765824B   primary   fat32        boot
 2      2146798080B   80015523839B  77868725760B  extended               lba
 5      2146830336B   38074821119B  35927990784B  logical   ntfs
 6      38074853376B  80015523839B  41940670464B  logical   ntfs

With this you can loop mount the file using the offset of the partition from the beginning of the file, e.g.:

~$ mount -o ro,loop,offset=2146830336 image-sdf-80G.bin /mnt/wantedpartition