initial commit

This commit is contained in:
2026-05-03 00:17:08 -04:00
parent 0c4ea2046e
commit eccbe4095f
35 changed files with 125 additions and 3438 deletions
+12 -47
View File
@@ -1,50 +1,15 @@
# Korg, reborn # Automated Channel Fault Analysis with Tofu
# TODO: ## Installation and Tests
- [x] nix flake here - Install nix
- [x] fix weird spin errors(?) - Run `nix develop`
- jake note: pinned specific working SPIN version using Nix - Execute the test harnesses with `test_harness.py`:
- [x] add attackers that only do specifically n queries
- limitation: you cannot choose only *n* queries for the dropping attacker; trace violations can happen at any time
- [x] add attackers to do <= n queries
- [x] add attackers that can do attacks with an unbounded number of messages
- [x] add a test suite
- [x] make the impl more robust; do more SWE
- [x] add no self-deadlock experiments
- I envision this would be: providing an eventually-style LTL query, sending messages onto an open channel, and asserting that the gadget doesn't somehow deadlock with itself
- [ ] support queries over multiple properties
- [ ] add raft, TCP, SCTP, ABP experiments from old Korg impl to the test suite
- [ ] add labels on trace logging to gadgets
- [ ] modify the paper? spin workshop?
# Notes ```
- Sound and complete attack discovery for replay, dropping, and reordering attacks on channels $ test_harness tests/tcp.yaml # TCP tests
- possible because of the finite-state modeling spin does. Indeed, we can model no-limit attackers within the finite-state model, giving guarantees of decidability and complexity. $ test_harness tests/abp.yaml # ABP tests
- Limiting the number of messages a drop/replay/reorder attacker can reason about has the ability to significantly reduce the searchspace, especially when dealing with larger models. Although KORG is always decidable, sound, and complete, using the unbounded attacker is inadvisable in practice because spin must reason about *all* such permutations of possible drop, replay, and reorder sequences, thereby increasing the search space factorially. $ test_harness tests/tests.yaml # general correctness tests
- One explicit limitation of the replay attacker is not being able to transition back to listening for packets after replaying ```
- Maybe change the title to: Korg: Automated analysis of channel faults Each test comes with a description - check out the respective YAML files
- The inclusion of the pass on chan functionality is required to ensure liveness properties are not trivially violated by an attacker gadget that loops with itself. Thus the pass on chan functionality is the best possible "wait" we could think up. We also include no deadlock tests.
# Gadget Structures A full tutorial is available in [TUTORIAL.MD](TUTORIAL.MD)
Drop:
- drop msg off chan
- pass on chan
Replay:
:CONSUME:
- consume msg; may go to CONSUME or REPLAY
- pass on chan
:REPLAY:
- replay msg
- pass on chan
- pass on chan, then go to REPLAY
Reorder:
:INIT:
- pass msg on chan
- go to CONSUME
:CONSUME:
- consume n messages on chan, then go to REPLAY
:REPLAY:
- replay msg
+101
View File
@@ -0,0 +1,101 @@
# Tutorial
Tofu synthesizes attacker gadgets (drop / replay / reorder) on top of an existing Promela model, then hands the combined model to Spin. If the LTL property breaks, the attacker found an attack.
## Setup
```
$ nix develop
```
The flake pins `nixpkgs` and a specific `spin` revision (see `flake.lock`), so the toolchain is reproducible across machines.
## CLI
```
python src/main.py \
--model=<path>.pml \
--attacker={drop,replay,reorder} \
--chan=<chan>[,<chan>...] \
--mem=<int|unbounded> \
--output=<path>.pml \
[--eval] [--cleanup] [--nocheck]
```
- `--mem` bounds the attacker's memory (number of messages it can buffer / drop). Use `unbounded` to remove the bound.
- `--chan` accepts a comma-separated list. Multi-channel arrays use `name:i` or `name:a-b`.
- `--eval` runs Spin on the output. `--cleanup` removes Spin artifacts (`pan*`, `*.trail`, `_spin_nvr.tmp`) and the output `.pml` after evaluation.
## Writing a Model
A model has three parts: a channel, a consumer that walks a state machine on that channel, and an LTL property.
Save as `tests/example/tut.pml`:
```promela
// INTENDED BEHAVIOR: violation under replay, mem=1
chan c = [8] of { byte };
byte q = 1;
init {
c!5;
}
active proctype consume() {
MAIN:
do
:: c ? 5 -> goto PROC1;
od
PROC1:
do
:: c ? 5 -> goto PROC2;
od
PROC2:
q = 0;
}
ltl proc {
always !(q == 0);
}
```
The honest channel only carries one `5`, so `consume` should stall at `PROC1`. A replay attacker with `mem=1` can re-emit the consumed `5`, advancing the consumer to `PROC2` and falsifying the property.
## Running the Tool
```
$ python src/main.py --model=tests/example/tut.pml \
--attacker=replay --chan=c \
--output=temp.pml --mem=1 --eval --cleanup
```
Outputs to look for in Spin's report:
| Spin output | Meaning |
|------------------------|------------------------------------------------------------------|
| `assertion violated` | LTL safety property violated (attack found) |
| `acceptance cycle` | LTL liveness violated (attacker stalls progress) |
| neither | No violation; attacker (at this `--mem`) cannot break the model |
For the model above, expect a property violation. Drop `--mem` to `0` or switch to `--attacker=drop` and the violation disappears — the attacker no longer has the budget.
## Test Harness
Each `tests/*.yaml` entry pins a command and its intended outcome:
```yaml
my-test:
- command: python src/main.py --model=tests/example/tut.pml --attacker=replay --chan=c --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: replay attacker can re-emit the consumed 5
```
Run the suite:
```
$ python test_harness.py tests/tests.yaml
$ python test_harness.py tests/tcp.yaml
$ python test_harness.py tests/abp.yaml
```
The harness diffs Spin's verdict against `intended` and prints a pass/fail summary.
Binary file not shown.
Binary file not shown.
-146
View File
@@ -1,146 +0,0 @@
# ==============================================================================
# Author : Jake Ginesin
# Authored : 14 June 2024
# Purpose : synthesize attacker gadgets for attackers that can drop,
# replay, and reorder messages on a channel
# ==============================================================================
import sys, re, subprocess, os, shutil
from typing import List
from utility import *
from model_generate import *
def show_help() -> None:
msg=(
"Usage: \n"
" python main.py [arguments] \n\n"
"Arguments: \n"
" --model=path/to/model.pml Promela model to generate attackers on\n"
" --attacker=[replay,drop,reorder] \n"
" --chan=[chan1, chan2:int, ...] Channels to synthesize attackers on. When specifying over ranges of\n"
" channels, you can give ranges or a list of values\n"
" --nocheck Don't check channel validity\n"
# " --nchan=[nat, nat, ...] If the channel is a set of channels, how many attackers to synthesize?\n"
" --mem=[num] Size of memory. Defaults to '3' \n"
" --mem=unbounded Use the unbounded memory gadget version (not recommended)\n"
" --output=path/to/file.pml Output file name\n"
" --eval Evaluate the outputted file with Spin\n"
" --cleanup Clean up the extra files spin creates, including Korg's \n"
)
print(msg)
# assert "syntax error" not in stdout, "there seems to be a syntax error in the model"
# assert "processes created" in stdout, "the spin model creates no processes ... check to see if it compiles"
def main() -> None:
args = sys.argv[1:]
if len(args) == 0 or args[0] in ["help", "--help", "-h", "-help"]:
show_help()
sys.exit()
mem = 3 # default
for arg in args:
if arg.startswith("--model="):
model_path = arg.split("=", 1)[1]
elif arg.startswith("--attacker="):
attacker = arg.split("=", 1)[1]
elif arg.startswith("--mem="):
mem_read = arg.split("=", 1)[1]
elif arg.startswith("--chan="):
chans = arg.split("=", 1)[1]
elif arg.startswith("--output="):
out_file = arg.split("=", 1)[1]
if "--eval" in args and not "--output" in args:
out_file = "korg-promela-out.pml"
if not model_path or not attacker or not mem or not chans or not out_file:
print("error: all arguments are required. \n")
show_help()
sys.exit(1)
unbounded = mem_read == "unbounded"
if not unbounded : mem = int(mem_read)
ensure_compile(model_path)
model = fileRead(model_path)
channels = parse_channels(fileReadLines(model_path))
mchannels, mchannel_len = parse_mchannels(fileReadLines(model_path))
model_with_attacker = str;
assert mem >= 0, "memory value must be positive"
chans_togen = set()
# first, process the input
mc = chans.split(",")
for chan in mc:
if ":" in chan:
name, num_extr = chan[:chan.index(":")], chan[chan.index(":")+1:]
if "-" in num_extr:
a, b = list(map(lambda a: int(a), num_extr.split("-")))
assert a < b
assert a >= 0
assert b < mchannel_len[name]
for i in range(a,b+1):
chan_name = str(name) + "[" + str(i) + "]"
chans_togen.add(chan_name)
channels[chan_name] = mchannels[name]
else:
a = int(num_extr)
assert a >= 0
assert a < mchannel_len[name]
chan_name = str(name) + "[" + str(a) + "]"
chans_togen.add(chan_name)
channels[chan_name] = mchannels[name]
else : chans_togen.add(chan)
print(chans_togen)
for i in range(len(chans_togen)):
chan = list(chans_togen)[i]
if not "--nocheck" : assert chan in channels, "can't find "+str(chan)+" in model"
match attacker:
case "replay":
if unbounded : attacker_gadget = gen_replay_unbounded(chan, channels[chan], i)
else : attacker_gadget = gen_replay(chan, channels[chan], mem, i)
case "drop":
if unbounded : attacker_gadget = gen_drop_unbounded(chan, channels[chan], i)
else : attacker_gadget = gen_drop(chan, channels[chan], mem, i)
case "reorder":
if unbounded : attacker_gadget = gen_reorder_unbounded(chan, channels[chan], i)
else : attacker_gadget = gen_reorder(chan, channels[chan], mem, i)
case _:
print("error: inputted an invalid attacker model. \n")
sys.exit(1)
if model.rindex("};") >= model.rindex("}"):
model = model[:model.rindex("};")+2] + "\n\n" + attacker_gadget + "\n" + model[model.rindex("};")+2:]
else:
model = model[:model.rindex("}")+1] + "\n\n" + attacker_gadget + "\n" + model[model.rindex("}")+1:]
# Write the modified model to the output file
with open(out_file, 'w') as file:
file.write(model)
if "--eval" in args:
print()
print("generated Promela file with attacker model gadget... now running SPIN on "+str(out_file) + "!\n")
eval_model(out_file)
if "--cleanup" in args:
print("\nCleaning up Spin files...")
cleanup_spin_files()
try:
os.remove(out_file)
print(f"Removed: {out_file}")
except OSError:
pass
if __name__== "__main__":
main()
+1 -2
View File
@@ -1,6 +1,5 @@
# ============================================================================== # ==============================================================================
# Author : Jake Ginesin # Author : [redacted]
# Authored : 14 June 2024
# Purpose : synthesize attacker gadgets for attackers that can drop, # Purpose : synthesize attacker gadgets for attackers that can drop,
# replay, and reorder messages on a channel # replay, and reorder messages on a channel
# ============================================================================== # ==============================================================================
+9
View File
@@ -0,0 +1,9 @@
unidirectional-drop-abp:
- command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol
bidirectional-drop-abp:
- command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol
-216
View File
@@ -1,216 +0,0 @@
# --- PHI 1: HALF-OPEN PREVENTION ---
tcp-phi1-drop-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: Dropping A's FIN allows A to eventually time out to Closed while B remains stranded in Established.
tcp-phi1-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Attacker has 0 memory budget; normal teardown prevents half-open states.
tcp-phi1-replay-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: Replaying a stale SYN from A forces B into an Established state while A is completely Closed.
tcp-phi1-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Replaying B's final teardown ACK is idempotent and harmlessly dropped by A, maintaining state sync.
tcp-phi1-reorder-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2
- intended: property violation
- explanation: Reordering A's SYN and FIN segments desynchronizes B's state machine, triggering a half-open state.
tcp-phi1-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Reorder attacker requires at least mem=2 to swap messages; mem=1 is insufficient.
# --- PHI 3: NO DEADLOCKS ---
tcp-phi3-drop-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Dropping B's SYN-ACK stalls A in SynSent and B in SynRec indefinitely without timeout recovery.
tcp-phi3-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Zero memory prevents dropping, allowing standard timers and handshakes to resolve without deadlocks.
tcp-phi3-replay-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Replaying FIN messages traps the receiver in an infinite loop of CloseWait/LastAck processing.
tcp-phi3-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Replaying an ACK during the Established state is cleanly ignored and does not halt liveness progress.
tcp-phi3-reorder-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2
- intended: acceptance cycle
- explanation: Swapping handshake messages (ACK before SYN) deadlocks both endpoints in intermediate waiting states.
tcp-phi3-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Attacker lacks the mem=2 budget required to execute a reorder attack.
# --- PHI 5: SYN_RECEIVED RESOLUTION ---
tcp-phi5-drop-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Dropping the final ACK of the 3-way handshake prevents B from ever resolving SynRec to Established.
tcp-phi5-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Without drop capabilities, the ACK arrives normally, resolving the SynRec state.
tcp-phi5-replay-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Replaying a SYN forces B to repeatedly trigger simultaneous open logic, preventing resolution.
tcp-phi5-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Replaying the final ACK simply provides redundant resolution signals, which satisfies the property.
tcp-phi5-reorder-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2
- intended: acceptance cycle
- explanation: Delivering A's final ACK before B has fully entered SynRec confuses the state machine, stalling resolution.
tcp-phi5-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Insufficient memory to reorder packets; handshakes process chronologically.
# --- PHI 6: STRICT CLOSING TRANSITIONS ---
tcp-phi6-drop-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: Dropping the ACK to the FIN causes a timeout that bypasses the strict Closing-to-Closed state sequence.
tcp-phi6-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Normal termination proceeds; Closing transitions accurately based on protocol rules.
tcp-phi6-replay-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: Replaying a FIN while in Closing forces an invalid transition to TimeWait instead of Closed.
tcp-phi6-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: 0 memory prevents injection of unexpected packets during the tear-down phase.
tcp-phi6-reorder-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2
- intended: property violation
- explanation: Swapping FINs during a simultaneous close alters the ACK delivery timing, violating the strict sequence.
tcp-phi6-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Mem=1 prevents the reordering of the close-sequence messages.
# --- PHI 7: SIMULTANEOUS CLOSE RESOLUTION ---
tcp-phi7-drop-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Dropping a FIN during a simultaneous close prevents one side from transitioning out of FinW1State.
tcp-phi7-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Zero memory prevents message dropping; both endpoints successfully reach ClosedState.
tcp-phi7-replay-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Replaying stale FINs traps the endpoint in a continuous processing loop, halting progress to ClosedState.
tcp-phi7-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Without replay capabilities, the simultaneous close resolves chronologically.
tcp-phi7-reorder-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2
- intended: acceptance cycle
- explanation: Swapping FIN and ACK segments out of order desynchronizes the simultaneous close, causing a deadlock.
tcp-phi7-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Mem=1 is insufficient to execute a reorder attack.
# --- PHI 8: ACTIVE CLOSE EVENTUALLY TERMINATES ---
tcp-phi8-drop-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Dropping the responder's ACK leaves the active closer permanently stranded in FinW1State.
tcp-phi8-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Normal teardown ensures the active closer receives its ACK and FIN.
tcp-phi8-replay-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: Replaying application data or FINs delays the final transition, breaking the eventual termination guarantee.
tcp-phi8-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=0
- intended: no violation
- explanation: Normal sequence guarantees the active closer reaches ClosedState.
tcp-phi8-reorder-violate:
- command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=reorder --chan=BtoA --output=temp.pml --eval --cleanup --mem=2
- intended: acceptance cycle
- explanation: Delivering the responder's FIN before the ACK confuses the state machine logic in FinW1State, stalling termination.
tcp-phi8-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=reorder --chan=BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Insufficient memory to alter the close sequence.
# --- PHI 9: HANDSHAKE CANNOT BE BYPASSED ---
# Note: This is a strict safety property guaranteed by the structure of the Promela model.
# The LISTEN state explicitly routes only to SYN_RECEIVED upon reading a SYN.
# No channel attacker (drop, replay, reorder) can force a direct jump to ESTABLISHED.
tcp-phi9-drop-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi9.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: Dropping messages halts progress but cannot force an illegal structural transition from Listen directly to Established.
tcp-phi9-replay-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi9.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: The model's Listen state only branches on SYN (transitioning to SynRec). Replaying ACKs or FINs results in skipped messages, not illegal state jumps.
tcp-phi9-reorder-pass:
- command: python src/main.py --model=tests/tcp/tcp-phi9.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2
- intended: no violation
- explanation: Regardless of message order, the Promela model restricts ListenState exits exclusively to SynRecState. This safety property is structurally immune to channel manipulation.
-109
View File
@@ -1,109 +0,0 @@
unidirectional-drop-abp:
- command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol
bidirectional-drop-abp:
- command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol
tcp-phi1-drop-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: dropping A's outbound messages alone is insufficient to create a half-open state; B cannot reach Established without receiving from A
tcp-phi1-drop-BtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: dropping B's outbound messages prevents B from progressing; A times out back to Closed, no half-open
tcp-phi1-drop-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: dropping on both directions prevents any handshake progress; neither side reaches Established
tcp-phi1-replay-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: replaying A's SYN can drive B into Established via a forged handshake while A returns to Closed, creating a half-open state
tcp-phi1-replay-BtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: replaying B's SYN+ACK can cause A to believe handshake completed; if A then closes, B may remain Established
tcp-phi1-replay-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: replaying on both channels gives the attacker maximum ability to manufacture a half-open state
tcp-phi1-reorder-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoN --output=temp.pml --eval --cleanup --mem=2
- intended: property violation
- explanation: reordering A's messages (e.g., delivering ACK before SYN) can desynchronize the handshake, leading to half-open
tcp-phi1-reorder-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=2
- intended: property violation
- explanation: reordering on both channels maximizes desynchronization potential for half-open
tcp-phi3-drop-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: dropping A's messages can cause B to stall indefinitely in SynReceived or similar waiting states
tcp-phi3-drop-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: dropping on both channels can strand both sides in intermediate states with no timeout recovery
tcp-phi3-replay-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: replaying stale messages can trap B in a loop re-processing old handshake messages
tcp-phi3-reorder-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=2
- intended: acceptance cycle
- explanation: reordering on both channels can desynchronize both sides into permanently mismatched states
tcp-phi5-drop-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: if A's ACK is dropped, B remains stuck in SynReceived with no timeout to recover
tcp-phi5-drop-BtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: acceptance cycle
- explanation: dropping B's SYN+ACK means A never sends ACK, leaving the initiator-side SynReceived unresolved
tcp-phi5-replay-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: replaying A's messages provides additional ACKs that can help resolve SynReceived
tcp-phi5-reorder-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoN --output=temp.pml --eval --cleanup --mem=2
- intended: acceptance cycle
- explanation: reordering can deliver A's SYN after the ACK, confusing B's state machine and trapping it in SynReceived
tcp-phi6-drop-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: no violation
- explanation: dropping A's messages while in Closing does not cause A to transition to an unexpected state; A remains in Closing or eventually times out
tcp-phi6-replay-AtoN:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: replaying a FIN while in Closing could cause a transition to TimeWait instead of the expected Closing or Closed
tcp-phi6-replay-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1
- intended: property violation
- explanation: replaying on both channels maximizes the chance of injecting an unexpected ACK that transitions Closing to TimeWait, violating the next-state constraint
tcp-phi6-reorder-bidirectional:
- command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=2
- intended: property violation
- explanation: reordering close-sequence messages can cause ACK delivery at unexpected times, violating the strict Closing transition property
+2
View File
@@ -0,0 +1,2 @@
Note:
- we do not expect properties 2, 4, and 6 to hold under this model.
-143
View File
@@ -1,143 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
/* safety: half-open prevention */
ltl phi1 {
always ( leftClosed implies !rightEstablished )
}
-143
View File
@@ -1,143 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
/* liveness: verifying connection establishment */
ltl phi2 {
( (always ( eventually ( state[0] == 1 && state[1] == 2 ) ) )
implies ( eventually ( state[0] == 4 ) ) )
-43
View File
@@ -1,43 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:121
2:1:114
3:0:121
4:1:115
5:0:121
6:1:116
7:0:121
8:1:117
9:0:121
10:3:0
11:0:121
12:3:1
13:0:121
14:3:2
15:0:121
16:3:9
17:0:121
18:2:0
19:0:121
20:2:1
21:0:121
22:2:2
23:0:121
24:2:9
25:0:121
26:3:17
27:0:121
28:3:1
-1:-1:-1
29:0:121
30:3:3
31:0:121
32:3:22
33:0:119
34:2:15
35:0:126
36:2:16
37:0:119
38:3:42
39:0:126
40:3:1
-161
View File
@@ -1,161 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
/* liveness: no infinite stalls/deadlocks */
ltl phi3 {
!(eventually (((always (state[0] == SynSentState)) ||
(always (state[0] == SynRecState)) ||
(always (state[0] == EstState)) ||
(always (state[0] == FinW1State)) ||
(always (state[0] == CloseWaitState)) ||
(always (state[0] == FinW2State)) ||
(always (state[0] == ClosingState)) ||
(always (state[0] == LastAckState)) ||
(always (state[0] == TimeWaitState)))
&&
((always (state[1] == SynSentState)) ||
(always (state[1] == SynRecState)) ||
(always (state[1] == EstState)) ||
(always (state[1] == FinW1State)) ||
(always (state[1] == CloseWaitState)) ||
(always (state[1] == FinW2State)) ||
(always (state[1] == ClosingState)) ||
(always (state[1] == LastAckState)) ||
(always (state[1] == TimeWaitState)))))
}
-62
View File
@@ -1,62 +0,0 @@
-2:3:-2
-4:-4:-4
1:0:289
2:2:122
3:0:289
4:2:123
5:0:289
6:2:124
7:0:289
8:2:125
9:0:289
10:4:0
11:0:289
12:4:1
13:0:289
14:4:2
15:0:289
16:4:9
17:0:289
18:3:0
19:0:289
20:3:1
21:0:289
22:3:2
23:0:289
24:3:9
25:0:289
26:4:17
27:0:289
28:4:1
29:0:289
30:4:3
31:0:289
32:4:22
33:0:289
34:1:116
35:0:289
36:1:117
37:0:289
38:3:10
39:0:289
40:3:11
41:3:12
42:0:289
43:3:47
44:0:249
45:1:114
46:0:599
47:1:115
48:0:599
49:4:40
50:0:599
51:4:41
52:0:599
53:1:114
54:0:599
55:1:115
56:0:599
57:4:31
-1:-1:-1
58:0:599
59:0:599
-150
View File
@@ -1,150 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
/* liveness: simultanous open */
ltl phi4 {
always (
(state[0] == SynSentState &&
state[1] == SynSentState)
implies
((eventually state[0] == EstState) &&
(eventually state[1] == EstState)))
}
-157
View File
@@ -1,157 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:122
2:1:114
3:0:122
4:1:115
5:0:122
6:1:116
7:0:122
8:1:117
9:0:122
10:3:0
11:0:122
12:3:1
13:0:122
14:3:2
15:0:122
16:3:9
17:0:122
18:2:0
19:0:122
20:2:1
21:0:122
22:2:2
23:0:122
24:2:9
25:0:122
26:3:17
27:0:122
28:3:1
29:0:122
30:3:3
31:0:122
32:3:22
33:0:122
34:2:10
35:0:122
36:2:11
37:2:12
38:0:122
39:3:23
40:0:122
41:3:24
42:0:122
43:3:25
44:0:122
45:3:55
46:0:122
47:3:56
48:0:122
49:3:66
50:0:122
51:2:47
52:0:122
53:2:48
54:0:122
55:2:55
56:0:122
57:2:56
58:0:122
59:3:67
60:0:122
61:3:68
62:0:122
63:3:94
64:0:122
65:2:66
66:0:122
67:2:67
68:0:122
69:2:68
70:0:122
71:3:95
72:0:122
73:3:110
74:0:122
75:3:1
76:0:122
77:3:2
78:0:122
79:2:94
80:0:122
81:2:95
82:0:122
83:2:110
84:0:122
85:2:1
86:0:122
87:2:3
88:0:122
89:3:9
90:0:122
91:3:10
92:0:122
93:3:11
94:3:12
95:0:122
96:3:47
97:0:122
98:2:22
99:0:122
100:2:23
101:0:122
102:2:24
103:0:122
104:2:25
105:0:122
106:3:48
107:0:122
108:3:55
109:0:122
110:3:56
111:0:122
112:2:55
113:0:122
114:2:56
115:0:122
116:2:66
117:0:122
118:3:66
119:0:122
120:3:67
121:0:122
122:3:68
123:0:122
124:2:67
125:0:122
126:2:68
127:0:122
128:2:94
129:0:122
130:3:94
131:0:122
132:3:95
133:0:122
134:3:110
135:0:122
136:3:1
137:0:122
138:3:3
139:0:122
140:3:22
141:0:122
142:2:95
143:0:122
144:2:110
145:0:122
146:2:1
147:0:122
148:2:3
149:0:122
150:3:23
151:0:122
152:3:27
153:0:122
154:2:22
155:0:119
-152
View File
@@ -1,152 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
/* liveness: SYN_RECEIVED resolution*/
ltl phi5 {
always (
(state[0] == SynRecState)
implies (
eventually (
(state[0] == EstState ||
state[0] == FinW1State ||
state[0] == ClosedState)
)
)
)
}
-64
View File
@@ -1,64 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:121
2:1:114
3:0:121
4:1:115
5:0:121
6:1:116
7:0:121
8:1:117
9:0:121
10:3:0
11:0:121
12:3:1
13:0:121
14:3:2
15:0:121
16:3:9
17:0:121
18:2:0
19:0:121
20:2:1
21:0:121
22:2:2
23:0:121
24:2:9
25:0:121
26:3:17
27:0:121
28:3:1
29:0:121
30:3:3
31:0:121
32:3:22
33:0:121
34:2:10
35:0:121
36:2:11
37:2:12
38:0:121
39:3:23
40:0:121
41:3:24
42:0:121
43:3:25
44:0:121
45:3:55
46:0:121
47:3:56
48:0:121
49:3:66
50:0:121
51:2:47
52:0:119
53:2:50
54:0:126
55:2:51
56:0:126
57:2:50
58:0:126
59:2:51
-1:-1:-1
60:0:126
61:0:126
-148
View File
@@ -1,148 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
/* safety: strict closing transitions */
ltl phi6 {
always (
(state[0] == ClosingState)
implies
(next (state[0] == ClosingState ||
state[0] == ClosedState))
)
}
-88
View File
@@ -1,88 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:121
2:1:114
3:0:121
4:1:115
5:0:121
6:1:116
7:0:121
8:1:117
9:0:121
10:3:0
11:0:121
12:3:1
13:0:121
14:3:2
15:0:121
16:3:9
17:0:121
18:2:0
19:0:121
20:2:1
21:0:121
22:2:2
23:0:121
24:2:9
25:0:121
26:3:17
27:0:121
28:3:1
29:0:121
30:3:3
31:0:121
32:3:22
33:0:121
34:2:10
35:0:121
36:2:11
37:2:12
38:0:121
39:3:23
40:0:121
41:3:24
42:0:121
43:3:25
44:0:121
45:3:55
46:0:121
47:3:56
48:0:121
49:3:66
50:0:121
51:2:47
52:0:121
53:2:48
54:0:121
55:2:55
56:0:121
57:2:56
58:0:121
59:3:67
60:0:121
61:3:68
62:0:121
63:3:94
64:0:121
65:2:66
66:0:121
67:2:67
68:0:121
69:2:68
70:0:121
71:3:95
72:0:121
73:3:110
74:0:121
75:3:1
76:0:121
77:3:2
78:0:121
79:3:9
80:0:121
81:2:94
82:0:121
83:2:95
84:0:119
85:2:110
86:0:126
-138
View File
@@ -1,138 +0,0 @@
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoB = [2] of { mtype };
chan BtoA = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoB, BtoA, 0);
run TCP(BtoA, AtoB, 1);
}
-149
View File
@@ -1,149 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
/* safety: half-open prevention */
ltl phi1 {
always ( leftClosed implies !rightEstablished )
}
-149
View File
@@ -1,149 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
/* liveness: verifying connection establishment */
ltl phi2 {
( (always ( eventually ( state[0] == 1 && state[1] == 2 ) ) )
implies ( eventually ( state[0] == 4 ) ) )
-55
View File
@@ -1,55 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:121
2:1:114
3:0:121
4:1:115
5:0:121
6:1:116
7:0:121
8:1:117
9:0:121
10:3:0
11:0:121
12:3:1
13:0:121
14:3:2
15:0:121
16:3:9
17:0:121
18:2:0
19:0:121
20:2:1
21:0:121
22:2:2
23:0:121
24:2:9
25:0:121
26:3:17
27:0:121
28:3:1
29:0:121
30:3:3
31:0:121
32:3:22
33:0:119
34:2:17
35:0:126
36:2:1
37:0:121
38:2:3
39:0:121
40:2:22
41:0:121
42:2:42
43:0:121
44:2:1
-1:-1:-1
45:0:121
46:2:2
47:0:121
48:2:9
49:0:119
50:2:17
51:0:126
52:2:1
-167
View File
@@ -1,167 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
/* liveness: no infinite stalls/deadlocks */
ltl phi3 {
!(eventually (((always (state[0] == SynSentState)) ||
(always (state[0] == SynRecState)) ||
(always (state[0] == EstState)) ||
(always (state[0] == FinW1State)) ||
(always (state[0] == CloseWaitState)) ||
(always (state[0] == FinW2State)) ||
(always (state[0] == ClosingState)) ||
(always (state[0] == LastAckState)) ||
(always (state[0] == TimeWaitState)))
&&
((always (state[1] == SynSentState)) ||
(always (state[1] == SynRecState)) ||
(always (state[1] == EstState)) ||
(always (state[1] == FinW1State)) ||
(always (state[1] == CloseWaitState)) ||
(always (state[1] == FinW2State)) ||
(always (state[1] == ClosingState)) ||
(always (state[1] == LastAckState)) ||
(always (state[1] == TimeWaitState)))))
}
-156
View File
@@ -1,156 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
/* liveness: simultanous open */
ltl phi4 {
always (
(state[0] == SynSentState &&
state[1] == SynSentState)
implies
((eventually state[0] == EstState) &&
(eventually state[1] == EstState)))
}
-43
View File
@@ -1,43 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:122
2:1:114
3:0:122
4:1:115
5:0:122
6:1:116
7:0:122
8:1:117
9:0:122
10:3:0
11:0:122
12:3:1
13:0:122
14:3:2
15:0:122
16:3:9
17:0:122
18:2:0
19:0:122
20:2:1
21:0:122
22:2:2
23:0:122
24:2:9
25:0:122
26:3:17
27:0:122
28:3:1
29:0:122
30:3:3
31:0:122
32:3:22
33:0:122
34:2:17
35:0:122
36:2:1
37:0:122
38:2:3
39:0:122
40:2:22
41:0:119
-158
View File
@@ -1,158 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
/* liveness: SYN_RECEIVED resolution*/
ltl phi5 {
always (
(state[0] == SynRecState)
implies (
eventually (
(state[0] == EstState ||
state[0] == FinW1State ||
state[0] == ClosedState)
)
)
)
}
-154
View File
@@ -1,154 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
/* safety: strict closing transitions */
ltl phi6 {
always (
(state[0] == ClosingState)
implies
(next (state[0] == ClosingState ||
state[0] == ClosedState))
)
}
-144
View File
@@ -1,144 +0,0 @@
// models: phi1, phi2, phi3, phi5
// does not model: phi4, phi7
// not yet implemented: phi6
mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN }
chan AtoN = [2] of { mtype };
chan NtoA = [2] of { mtype };
chan BtoN = [2] of { mtype };
chan NtoB = [2] of { mtype };
int state[2];
int pids[2];
#define ClosedState 0
#define ListenState 1
#define SynSentState 2
#define SynRecState 3
#define EstState 4
#define FinW1State 5
#define CloseWaitState 6
#define FinW2State 7
#define ClosingState 8
#define LastAckState 9
#define TimeWaitState 10
#define EndState -1
#define leftConnecting (state[0] == ListenState && state[1] == SynSentState)
#define leftEstablished (state[0] == EstState)
#define rightEstablished (state[1] == EstState)
#define leftClosed (state[0] == ClosedState)
proctype TCP(chan snd, rcv; int i) {
pids[i] = _pid;
CLOSED:
state[i] = ClosedState;
do
/* Passive open */
:: goto LISTEN;
/* Active open */
:: snd ! SYN; goto SYN_SENT;
/* Terminate */
:: goto end;
od
LISTEN:
state[i] = ListenState;
do
:: rcv ? SYN ->
atomic {
snd ! SYN;
snd ! ACK;
goto SYN_RECEIVED;
}
/* Simultaneous LISTEN */
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED;
od
SYN_SENT:
state[i] = SynSentState;
do
:: rcv ? SYN;
if
/* Standard behavior */
:: rcv ? ACK -> snd ! ACK; goto ESTABLISHED;
/* Simultaneous open */
:: snd ! ACK; goto SYN_RECEIVED;
fi
:: rcv ? ACK;
do
:: rcv ? SYN ->
snd ! ACK;
goto ESTABLISHED;
:: rcv ? _ -> skip;
od
:: rcv ? _ -> skip;
:: timeout -> goto CLOSED; /* Timeout */
od
SYN_RECEIVED:
state[i] = SynRecState;
do
:: rcv ? ACK -> goto ESTABLISHED;
:: rcv ? _ -> skip;
od
/* We may want to consider putting a timeout -> CLOSED here. */
ESTABLISHED:
state[i] = EstState;
do
/* Close - initiator sequence */
:: snd ! FIN; goto FIN_WAIT_1;
/* Close - responder sequence */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSE_WAIT;
:: rcv ? _ -> skip;
od
FIN_WAIT_1:
state[i] = FinW1State;
do
/* Simultaneous close */
:: rcv ? FIN ->
snd ! ACK;
goto CLOSING;
/* Standard close */
:: rcv ? ACK -> goto FIN_WAIT_2;
:: rcv ? _ -> skip;
od
CLOSE_WAIT:
state[i] = CloseWaitState;
do
:: snd ! FIN; goto LAST_ACK;
:: rcv ? _ -> skip;
od
FIN_WAIT_2:
state[i] = FinW2State;
do
:: rcv ? FIN ->
snd ! ACK;
goto TIME_WAIT;
:: rcv ? _ -> skip;
od
CLOSING:
state[i] = ClosingState;
do
:: rcv ? ACK -> goto TIME_WAIT;
:: rcv ? _ -> skip;
od
LAST_ACK:
state[i] = LastAckState;
do
:: rcv ? ACK -> goto CLOSED;
:: rcv ? _ -> skip;
od
TIME_WAIT:
state[i] = TimeWaitState;
goto CLOSED;
end:
state[i] = EndState;
}
init {
state[0] = ClosedState;
state[1] = ClosedState;
run TCP(AtoN, NtoA, 0);
run TCP(BtoN, NtoB, 1);
}
BIN
View File
Binary file not shown.
-192
View File
@@ -1,192 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:139
2:1:130
3:0:139
4:1:131
5:0:139
6:1:132
7:1:133
8:0:139
9:3:0
10:0:139
11:3:1
12:0:139
13:3:6
14:0:139
15:2:0
16:0:139
17:2:1
18:0:139
19:2:6
20:0:139
21:3:16
22:0:139
23:3:0
24:0:139
25:3:2
26:0:139
27:3:21
28:0:139
29:2:7
30:0:139
31:2:8
32:0:139
33:2:9
34:0:139
35:3:22
36:0:139
37:3:23
38:0:139
39:3:24
40:0:139
41:3:49
42:0:139
43:2:10
44:0:139
45:3:50
46:0:139
47:3:51
48:0:139
49:3:62
50:0:139
51:3:63
52:0:139
53:3:76
54:0:139
55:2:49
56:0:139
57:2:50
58:0:139
59:2:51
60:0:139
61:2:62
62:0:139
63:2:63
64:0:139
65:3:77
66:0:139
67:3:78
68:0:139
69:3:79
70:0:139
71:3:102
72:0:139
73:2:76
74:0:139
75:2:77
76:0:139
77:2:78
78:0:139
79:2:79
80:0:139
81:3:103
82:0:139
83:3:104
84:0:139
85:3:127
86:0:139
87:3:0
88:0:139
89:3:1
90:0:139
91:2:102
92:0:139
93:2:103
94:0:139
95:2:104
96:0:139
97:2:127
98:0:139
99:2:0
100:0:139
101:2:2
102:0:139
103:3:6
104:0:139
105:3:7
106:0:139
107:3:8
108:0:139
109:3:9
110:0:139
111:3:10
112:0:139
113:3:49
114:0:139
115:2:21
116:0:139
117:2:22
118:0:139
119:2:23
120:0:139
121:2:24
122:0:139
123:3:50
124:0:139
125:3:51
126:0:139
127:3:62
128:0:139
129:3:63
130:0:139
131:2:49
132:0:139
133:2:50
134:0:139
135:2:51
136:0:139
137:2:62
138:0:139
139:2:63
140:0:139
141:2:76
142:0:139
143:3:76
144:0:139
145:3:77
146:0:139
147:3:78
148:0:139
149:3:79
150:0:139
151:2:77
152:0:139
153:2:78
154:0:139
155:2:79
156:0:139
157:2:102
158:0:139
159:3:102
160:0:139
161:3:103
162:0:139
163:3:104
164:0:139
165:3:127
166:0:139
167:3:0
168:0:139
169:3:2
170:0:139
171:3:21
172:0:139
173:2:103
174:0:139
175:2:104
176:0:139
177:2:127
178:0:139
179:2:0
180:0:139
181:2:2
182:0:139
183:3:22
184:0:139
185:3:23
186:0:139
187:3:24
188:0:139
189:2:21
190:0:136
-102
View File
@@ -1,102 +0,0 @@
-2:2:-2
-4:-4:-4
1:0:138
2:1:130
3:0:138
4:1:131
5:0:138
6:1:132
7:1:133
8:0:138
9:3:0
10:0:138
11:3:1
12:0:138
13:3:6
14:0:138
15:2:0
16:0:138
17:2:1
18:0:138
19:2:6
20:0:138
21:3:16
22:0:138
23:3:0
24:0:138
25:3:2
26:0:138
27:3:21
28:0:138
29:2:7
30:0:138
31:2:8
32:0:138
33:2:9
34:0:138
35:3:22
36:0:138
37:3:23
38:0:138
39:3:24
40:0:138
41:3:49
42:0:138
43:2:10
44:0:138
45:3:50
46:0:138
47:3:51
48:0:138
49:3:62
50:0:138
51:3:63
52:0:138
53:3:76
54:0:138
55:2:49
56:0:138
57:2:50
58:0:138
59:2:51
60:0:138
61:2:62
62:0:138
63:2:63
64:0:138
65:3:77
66:0:138
67:3:78
68:0:138
69:3:79
70:0:138
71:3:102
72:0:138
73:2:76
74:0:138
75:2:77
76:0:138
77:2:78
78:0:138
79:2:79
80:0:138
81:3:103
82:0:138
83:3:104
84:0:138
85:3:127
86:0:138
87:3:0
88:0:138
89:3:1
90:0:138
91:3:6
92:0:138
93:2:102
94:0:138
95:2:103
96:0:138
97:2:104
98:0:136
99:2:127
100:0:143