Skip to content

0.4.0

Latest

Choose a tag to compare

@github-actions github-actions released this 01 Aug 12:31
· 26 commits to master since this release
fad537e

If it saved you time, leave a star. That is how the next tester who needs it finds out it exists.
BeanStar

The short version. This release is about numbers you can trust and targeting that catches what
you aimed at. If you read nothing else:

  • Aiming at a process now catches a connection from its first packet, TCP and UDP alike.
    "Drop SYN" combined with a process target previously did nothing at all, and DNS and QUIC walked
    past untouched.
  • "Effective loss" was wrong and is now right. It counts every impairment, over the traffic you
    aimed at. A session losing 90% of its traffic to a speed limit used to report 0.0%.
  • Presets and the shipped scenarios were recalculated against published measurements. Latency
    was applied twice, and three presets were eight times too fast.
  • A session moves about 1.3x more packets a second, and a delay you ask for arrives without the
    old few-millisecond surcharge.
  • New: "Capture only the targeted traffic". On a real run without it, the driver threw away 43%
    of the traffic you had aimed at before this tool ever saw it.
  • New: "Show only the targeted traffic", five new presets, a "Driver queue wait" reading, and a
    warning when your target shares a port with another program.
  • Config and scenario files now reject a typo instead of ignoring it.
  • Plus a long list of fixes to the counters, the Connections table and session start/stop.

If you script this tool, read the BREAKING section: presets, "Effective loss", profiles, the
statistics CSV, the connections CSV and the reproduction report all changed shape or meaning.

BREAKING

  • A misspelled setting in a config file is now an error. "latancy": 300 used to load in
    silence, so --dry-run said "Configuration is valid" and the run went out with no latency at
    all. Unknown settings now fail with code 3, naming the key and suggesting the near miss. Files
    this tool saved keep loading. A hand-written file with an unknown name will not.

  • A mistake in a scenario file now says so instead of doing nothing. "duraton" used to leave a
    reset at its default and "lop" used to turn looping off, both silently, so the tool looked like
    it was ignoring your file. Unknown keys, in a step or at the top level, are now an error naming
    the key. A correct file keeps working.

  • A scenario that ends now ends the run. A non-looping scenario with a timeline used to print
    "Scenario finished." and then run forever, which in a pipeline is a job that hangs to its own
    timeout and writes no summary. Such a run now stops with stop_reason: "scenario_done" and says
    so at the start. --duration still wins wherever you pass it.

  • The old reset_now scenario action is gone. reset_tcp does the same thing and is now the
    only action. A file still using reset_now will not load and says which step to fix. The
    "Reset TCP now" button is unaffected.

  • The presets were wrong and are now checked against published measurements. Latency was set as
    if it were a ping, but it is added in both directions, so "Satellite link" at 600 ms delivered a
    1200 ms ping. Three presets held kilobits where the field wants kilobytes, making them
    eight times too fast. If you scripted --preset, your traffic changes. Ids are unchanged, but
    --preset "Satellite link" is now "Satellite (geostationary)".

  • The shipped scenarios in scenarios/ were recalculated the same way, so a scenario and a
    preset describe the same network with the same numbers. The ping you get is now the number written
    in the file.

  • "Effective loss" now means what its name says, and your numbers will change. It used to be the
    configured Loss percentage over every packet seen, ignoring speed limits, blocking, LAN cut, link
    outages, resets, dropped SYNs and expired NAT. It now counts every impairment, over the traffic you
    aimed at. effective_loss_pct and effective_corruption_pct moved with it, so reports from before
    and after are not comparable.

  • "Duplicated" counts packets actually sent twice, not packets the tool decided to duplicate.
    Under load the copy was thrown away while the counter rose anyway: 40 packets in, "Duplicated"
    read 40, nothing reached the wire. This matches "Corrupted", which always counted only real
    changes. Reports from before and after are not comparable on that field.

  • Profiles now remember more of the link: latency spikes, link outages (flapping) and the buffer,
    on top of the original seven fields. Outages are why it was worth doing - a profile can finally
    describe a link that cuts out. Old profiles load exactly as before. Picking a preset now clears
    all of these, so "Perfect network" really does clear everything, and --preset finally does what
    the window does.

  • The Connections table now shows what arrived AND what was offered. "down", "up" and "total"
    held captured bytes under headings meaning delivered, so a row could read 5 MB while the
    application got 0.4 MB. Those three are now delivered, and new "down seen" / "up seen"
    hold what was captured. The connections CSV changed shape: the three old byte columns are
    replaced by six delivered_* and captured_* ones, renamed rather than reused.

  • The reproduction report's "connections reset" counted packets, not connections. One reset
    connection could report itself as 50. The report now carries three keys that answer three
    questions: connections_reset, rst_packets_dropped and rst_sent. The statistics CSV gained a
    matching connections_reset column. Nothing on screen changed.

  • The statistics CSV gained capture_narrowed and packets_in_scope columns. The first records
    whether "Capture only the targeted traffic" was in effect, without which two rows under one header
    can count completely different traffic. Your existing file is moved aside with a timestamp and a
    fresh one started, as it already is whenever columns change, so no row misaligns. A script reading
    by column position needs the new offsets.

  • --gui no longer accepts any other option. --gui --loss 30 --duration 600 used to open no
    window and quietly impair in the background, with no STOP button anywhere. It now stops with a
    usage error (code 2) and says what to do instead. If a script relied on this, delete --gui
    from it.

Added

  • Five new presets: Satellite (low orbit), Distant server (another continent), Congested home
    link (bufferbloat), Train / metro (tunnels) and In-flight Wi-Fi. Two are worth a note: bufferbloat
    only bites once you really saturate the link, and Train / metro is the only preset that takes the
    connection fully down, so your application has to reconnect rather than just slow down.

  • "Show only the targeted traffic" (Settings, off by default) points the counters, the chart, the
    Connections table and the connections CSV at your target alone. It changes what you see, never
    what is captured or impaired. Three things deliberately do not follow it: "Queue overflow",
    "Dropped at stop" and "Send failed" always cover everything, because they count the tool's own
    losses. The statistics CSV carries both totals instead. Reports and --format json are unchanged.

  • "Capture only the targeted traffic" (--narrow-filter) pushes your destination IP and port
    into WinDivert, so traffic that could never be impaired is not handed over at all. It is a
    correctness fix, not just a speed one: measured on a real run, without it the driver threw away
    43% of the traffic you aimed at before the tool saw it. It applies at START, and does nothing
    for a process target, a wildcard or an re: pattern - the run says which.

  • "Driver queue wait (peak)" in the Session tab shows how long packets waited inside WinDivert
    before the tool saw them. That is the one delay the tool adds and counted nowhere. It is measured,
    not estimated. Expect a fraction of a millisecond when idle; above 50 ms the log says so. Blank
    under --simulate.

  • A session now records the WinDivert queue it ran behind (length, time and size) in the log and
    in the reproduction report, so a report from a machine you do not have in front of you says which
    queue produced its numbers.

  • The tool now warns when your target shares a port with another program. Windows lets several
    programs hold one local port - that is how mDNS, SSDP and DHCP work - and this tool decides what to
    break from the port number. On this machine four ports out of 127 were shared, one of them by five
    programs. Applying a target now names the port and who holds it, so you know that part of the
    result is a coin toss.

  • The command line says when your target stops matching, instead of finishing green in silence.
    Measured: aiming by process id and restarting the program left five out of five new connections
    untouched with nothing in the output. Aiming by name recovers on its own and costs only the
    first connection. Aiming by process id never recovers. If the program under test restarts, aim
    by name.

  • Every run with a process target ends by saying how much of the captured traffic was yours -
    "In scope: 40 of 500 captured packets" - and calls it out when that is zero. A run where your
    target caught nothing looks exactly like a run where your application coped. It is a warning, not
    a failure, because a quiet target is perfectly ordinary.

Changed

  • The checkbox is now called "Capture only the targeted traffic", not "Narrow the driver filter
    to the target". The old name described the machinery. The --narrow-filter flag is unchanged, and
    its tooltip was rewritten to say what it does and when it will not apply.

  • A session moves about a third more packets a second. The tool handles packets on two threads,
    and Python left one waiting up to 5 ms for its turn - that waiting, not the work, was the limit. A
    session now asks for shorter turns and hands the setting back at STOP. Measured on loopback and a
    real card: 1.33x to 1.36x, in 24 comparisons out of 24, at slightly less processor time per
    packet.

  • A packet you did not ask to change goes back on the wire exactly as it arrived, and the session
    moves about 12% more traffic for it. Checksums used to be recomputed for every packet, including
    untouched ones, which also meant a session with nothing configured did not quite pass traffic
    through unchanged. Measured: 1.12x more packets a second, 8 comparisons out of 8, and 24 MiB of
    TCP arrived byte for byte over a real card.

  • Targeting a process no longer competes with the traffic it is measuring. Working out which
    sockets belong to your target used to happen on the thread handling your packets, dozens of times a
    second. It now runs on its own thread. A freshly opened connection is still impaired within tens of
    milliseconds and STOP stays immediate.

  • Semicolons are gone from the interface texts and both READMEs. Twenty-one tooltips and about
    eighty lines of documentation used them to join sentences, which is not how people write. Code
    samples keep theirs, where a semicolon is syntax.

  • "Spike chance" and "Spike size" moved to "Latency (ping)" from "Advanced (NAT / connections)",
    because a spike is latency. Nothing about how they work changed, nor their flags, nor their place
    in a profile.

  • "Blocking (firewall)" starts collapsed on a fresh install, like the other advanced panels. If
    you have used the tool before, your own choices are remembered.

  • The Latency and Jitter tooltips say the thing that was easy to get wrong: ping rises by about
    twice the latency you set, because both the request and the reply are delayed, while jitter widens
    the wobble by about 1.4x rather than doubling it. Both READMEs explain it too.

Fixed

  • Aiming at a process missed the first packet of every new connection. Measured: 20 fresh
    connections with "Drop SYN" at 100% produced 20 successful connections and not one dropped SYN, so
    "Drop SYN" plus a process target did nothing at all. The first packet is now checked against
    the live socket map.
    What changes for you: connections aimed at a process now take longer to open and a minority
    fail outright, which is what a bad network does. If a test measured "time to first byte" under
    impairment, expect it to move.

  • Aiming at a process did not touch the first packet of a UDP exchange - and DNS and QUIC take a
    fresh port every time, so it did not touch them at all. If you tested a game, a video call or a
    browser over QUIC and the impairment seemed weaker than configured, this is why. Ordinary TCP data
    is deliberately still not re-checked: measuring showed it would cost throughput for nothing.

  • The live "which app owns this port" map could be dragged backwards by a stale reading, so a
    connection was briefly credited to the wrong application. A periodic sweep of the socket table,
    always a little behind, was applied on top of the live signal from the driver. Measured over 25
    seconds of ordinary traffic: 919 times. Readings are now weighed by when they were taken.

  • Targeting could follow a process id after the process was gone, and Windows hands those numbers
    out again. A restarted target could come back under a remembered number and not be impaired,
    while an unrelated program inheriting that number was. The tool now checks the process is still
    the same one, and forgets it when it closes its last connection.

  • Three fixes to short-lived and freshly opened connections. Targeting now follows the system's
    socket events instead of scanning a few times a second, so a connection that opens and closes
    between two scans is no longer missed. The Connections table fills in the owning program from the
    first packet instead of leaving the row blank. And setting a process target no longer makes the
    first START pause for a second or two.

  • The "impaired?" column now reflects the whole session, not just this instant. It asked whether
    the port was in the target right now, so a row flipped to "no" the moment its connection closed
    and a run impairing all of Chrome looked like it caught almost nothing. The column, the row
    highlight, the sort and the CSV now read one record, so they cannot disagree.

  • The tool kept pausing itself and then blaming WinDivert. Every so often it spent up to half a
    second working out which program owns which connection, stopped collecting packets while it did,
    and then told you the driver's queue was backing up and to narrow your filter. The delay was its
    own. Measured over 95 seconds with programs constantly starting: the worst pile-up dropped from
    508 ms to 17 ms and the warning stopped appearing.

  • The "driver held a packet" warning described lost accuracy when what you were losing was
    traffic.
    Measured on a deliberately overloaded run: at 138,000 packets a second offered, the tool
    moved about 14,000 and 91.75% was thrown away by the driver before the tool saw it, while every
    drop counter on screen read zero. The warning now says a full driver queue means dropped packets,
    not just late ones.

  • With "Capture only the targeted traffic" on, the Statistics and Connections tabs said the exact
    opposite of the truth
    , keeping their "counters cover ALL captured traffic" line while the driver
    had been told to hand over nothing else. The checkbox tooltip promised the opposite and both
    READMEs contradicted themselves. Both notes, the chart caption and the READMEs now describe what
    the figures actually cover, including the case where a process target is set as well.

  • Four fixes to the Scope settings. The two "only the targeted traffic" switches now sit in one
    Scope card instead of separate panels a few rows apart, with a line that tells you before
    START
    whether your destination can actually be narrowed. The Settings window scrolls, so no group
    falls off the bottom. Starting a session logs which of the two outcomes you got. And the Session
    panel gained a "Capture" row, so a saved run says which traffic it counted.

  • Three counters were lying about how much was lost. "Buffer overflow" and "Dropped at stop"
    charged for duplicate copies as well as packets, so a run duplicating everything reported nearly
    twice as many dropped as captured. A connection's "dropped" count ignored packets its own queue
    threw away. And packets the tool failed to re-inject left the arithmetic entirely - those now have
    a "Send failed" counter, a banner and an event-log entry, throttled so they cannot flood the
    log.

  • Three tooltips were telling you things that were not true. "Dropped" claimed to count link
    outages, which have had their own counter for a while. "Downloaded (MB)" promised a figure that
    never appeared. And "Effective loss" read as "never reached the far end" when it measures damage
    done on this machine - loss out in the network never arrives here, so nothing here can count it.
    No numbers changed.

  • The delay you set is the delay you get. Windows rounds up the wait used to hold a packet back,
    and it was a fixed surcharge rather than a percentage, so it barely showed at 100 ms and swamped
    small settings. Measured with a plain ping: asking for 10 ms used to cost 12.6 ms extra and now
    costs 1 ms, the same 1 ms as at 50 ms. Jitter below about 15 ms used to vanish into the noise.

  • Long cut-offs and NAT blackouts now last as long as you set them. The tool forgets a connection
    it has not seen for a while, and a forgotten connection looks brand new - so a reset cooldown above
    about half a minute resumed after roughly 30 seconds however long you asked for, and "NAT mapping
    expiry" at 30 seconds never blocked a single packet.

  • "NAT mapping expiry" now really cuts the incoming direction. The packet rejected for "the
    mapping has expired" was itself counted as activity, so the mapping reopened on the spot: an app
    that never sent a keep-alive lost about one packet every five seconds and otherwise worked, passing
    a test it should have failed. Incoming traffic now stays cut until the application sends something.

  • "Reset connections" now works where it claimed to. It no longer fires on a connection that is
    still opening, where the forged reset carries no acknowledgement number and Windows is entitled to
    ignore it - measured, the connection hung until its own timeout. And it now really resets local
    (loopback) connections
    , which previously just went quiet for the cooldown while the tool reported
    an RST as sent. Connections to other machines were never affected.

  • Ping traffic never appeared in the Connections tab, which claims to list all of them - anything
    without ports was silently left out. Thirty seconds of pinging left the tab empty while the
    counters ticked up beside it. Portless traffic is now listed as one row per address with the port
    cells empty.

  • The Connections tab could empty itself instead of dropping its oldest rows. When many rows
    carried the same timestamp they all fell on the same side of the "old" estimate, so far more went
    than intended - in the extreme, everything. It now refuses to drop below the level it is trimming
    to.

  • When the capture could not start, the tool told you the wrong reason. A handle that failed to
    open produced WinDivert handle is not open - a symptom naming nothing - while the real cause went
    to a diagnostic file nobody reads. The helpful messages both interfaces already had, including the
    window's "run as Administrator" hint, could therefore never appear. Starting now fails immediately,
    with the reason.

  • Four ways a session mishandled its own start and stop. A failed start could leave the tool
    holding your traffic without impairing it, refusing every later START. Ending a session kept hold
    of your traffic for a moment while tidying up, so a connection could stall. STOP could take two
    seconds in two different races. And the log could print a fault above its own "Start" line.

  • An unforeseen error during a run is now an exit code, not a stack trace. A failure inside the
    reporting loop escaped as a raw traceback with code 1, which is also "the session could not
    start", so a pipeline could not tell an internal bug from a driver that would not open. It is now
    runtime (1) with a line saying what happened, and the run still writes its complete
    summary
    - a --format json file no longer ends mid-stream.

  • Three fixes to --dry-run and --doctor claiming more than they checked. --dry-run said
    "Configuration is valid" about a command that then exits 7, so it now says which half it checked
    and points at --doctor. It also reads your --scenario file now, which it never opened.
    --doctor no longer calls a driver "not loaded" when Windows simply refused to let it look.

  • Three fixes to the shared-port warning. It listed your own target among the strangers, because
    a program like Chrome runs several processes. It offered two possible outcomes when the socket
    table already decides which one applies. And it printed bare numbers, so 5353 read like a fault
    rather than mDNS. It now says 5353 (mDNS), names the program, and states the one outcome that is
    true.

  • Three files could stop the program from starting, and no longer do. A translation file with a
    malformed header, a window-layout file with an entry in the wrong shape, and a --config file that
    was valid JSON but not a set of settings - the last one reported the tool as having crashed. Each
    is now skipped or reported clearly, and the rest of your setup is kept.

  • Four smaller interface fixes. The throughput chart could be squeezed until it vanished on a
    narrow window (the Live tab now scrolls). "Close" was cut in half at the bottom of the Settings
    window. The profile picker cut long names off at 24 characters. And "Save profile..." opens with
    the cursor already in the name box.

  • Two things left litter behind. A failed "Export connections CSV" left a stray .tmp file next
    to the real one, and stopping a session could file a crash report in crashes/ for an ordinary
    STOP. Neither happens now.

  • Starting a second scenario without stopping the first is no longer possible. The engine
    replaced the running one and left the old one going in the background, so two scenarios fought over
    the same settings. Nothing in the program does this today, so it is a guard rather than a bug you
    could have hit.

Docs

  • Both READMEs now document the scenario file format, the seven shipped scenarios, both CSV exports
    and all 17 Connections columns
    - none of which were written down anywhere. The column meanings
    existed only as tooltips, and the CSV headers only in the code.

  • Three corrections to what the READMEs claimed. A connection is in scope "the moment it opens"
    only for a program the tool already recognises, not for that program's first connection. An
    exclusion like !chrome also covers every connection whose owner could not be identified, so do
    not use one to protect an application - name the one you do want broken. And both files explained
    greyed-out fields with an "Enable" checkbox that no longer exists.

  • The Requirements and Tests sections now match reality. psutil is not what makes process
    targeting work on Windows - the socket table and process names come from the OS, and targeting
    keeps working without it. Source installs work on Python 3.10 and newer while CI tests and builds
    on 3.14 only, which is the version frozen into the released .exe. The Tests section also now
    covers the GUI render check and how a release is produced.