From ff1bf88eb876962eeefc8d21f42526c34d32ee74 Mon Sep 17 00:00:00 2001 From: selysecr332 Date: Tue, 16 Jun 2026 22:04:11 +0300 Subject: [PATCH 1/4] docs(lab4): add submission template Signed-off-by: selysecr332 --- submissions/lab4.md | 189 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 submissions/lab4.md diff --git a/submissions/lab4.md b/submissions/lab4.md new file mode 100644 index 000000000..1d94095fe --- /dev/null +++ b/submissions/lab4.md @@ -0,0 +1,189 @@ +# Lab 4 — OS & Networking: Trace, Debug, and Read the Substrate + +**Student:** Mahmoud Hassan (`selysecr332`) +**Environment:** Windows 11 + **WSL2 Ubuntu** (required for `tcpdump`, `ss`, `dig`) + +--- + +## Task 1 — Trace a request end-to-end + +### 1.1 Capture setup + +_Terminal layout (all inside WSL):_ + +```bash +cd /mnt/c/Users/Selysecr/Desktop/DevOps/My_DevOps-Intro/DevOps-Intro/app +``` + +| Terminal | Command | +|----------|---------| +| A | `go run .` | +| B | `sudo tcpdump -i lo -nn -s 0 -A 'tcp port 8080' -w lab4-trace.pcap` | +| C | `curl -v -X POST http://localhost:8080/notes -H 'Content-Type: application/json' -d '{"title":"trace me","body":"in flight"}'` | + +### 1.2 Annotated capture (`lab4-trace.txt`) + +_TODO — paste excerpts after running:_ + +``` +sudo tcpdump -r lab4-trace.pcap -nn -A | tee lab4-trace.txt +``` + +| Phase | Packet evidence | Notes | +|-------|-----------------|-------| +| TCP handshake (SYN → SYN/ACK → ACK) | _TODO_ | | +| HTTP request (`POST /notes HTTP/1.1` + JSON body) | _TODO_ | | +| HTTP response (`HTTP/1.1 201 Created` + JSON) | _TODO_ | | +| Connection close (FIN / RST) | _TODO_ | | + +### 1.3 Five debugging commands + +**1. What's listening?** + +```bash +ss -tlnp | grep :8080 +``` + +``` +_TODO output_ +``` + +**2. Routes from host** + +```bash +ip route show +``` + +``` +_TODO output_ +``` + +**3. Reachability (loopback)** + +```bash +mtr -rwc 5 localhost +``` + +``` +_TODO output_ +``` + +**4. DNS works** + +```bash +dig +short example.com @1.1.1.1 +``` + +``` +_TODO output_ +``` + +**5. Logs (if service installed)** + +```bash +journalctl --user -u quicknotes -n 20 || true +``` + +``` +_TODO output_ +``` + +### 1.4 If QuickNotes returned 502 — what to check first? + +_TODO — one paragraph._ + +--- + +## Task 2 — Outside-in debugging on a broken deploy + +### 2.1 Reproduce broken instance + +```bash +cd app/ +ADDR=:8080 go run . & +PID1=$! +sleep 1 +ADDR=:8080 go run . 2>&1 | tee /tmp/qn-broken.log & +PID2=$! +sleep 2 +ps -ef | grep "go run" | grep -v grep +``` + +**Bind error captured:** + +``` +_TODO — paste exact error from /tmp/qn-broken.log_ +``` + +### 2.2 Outside-in chain + +| Step | Command | Output | Decision | +|------|---------|--------|----------| +| 1 — process running? | `ps -ef \| grep quicknotes` | _TODO_ | _TODO_ | +| 2 — listening? | `ss -tlnp \| grep 8080` | _TODO_ | _TODO_ | +| 3 — reachable? | `curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/health` | _TODO_ | _TODO_ | +| 4 — firewall? | `sudo iptables -L -n -v` or `sudo nft list ruleset` | _TODO_ | _TODO_ | +| 5 — DNS? | `dig +short localhost` | _TODO_ | _TODO_ | + +### 2.3 Repair + re-verify + +```bash +kill $PID1 +sleep 1 +ADDR=:8080 go run . & +sleep 1 +curl -s http://localhost:8080/health +``` + +``` +_TODO — health response after fix_ +``` + +### 2.4 Mini-postmortem (≤ 200 words) + +_TODO — blameless: systemic cause + tooling that could prevent port conflicts._ + +--- + +## Bonus — TLS handshake (optional) + +_Not started._ + +--- + +## Submission — Pull requests + +| PR | URL | +|----|-----| +| **Course** (`feature/lab4` → `inno-devops-labs/main`) | _TODO_ | +| **Fork** (`feature/lab4` → `selysecr332/main`) | _TODO_ | + +**Moodle:** submit both URLs before the deadline. + +--- + +## Lab 4 completion checklist + +### Task 1 (6 pts) + +- [ ] `lab4-trace.pcap` / annotated `lab4-trace.txt` +- [ ] TCP handshake, HTTP req/resp, close identified +- [ ] Five debug commands with output +- [ ] 502 reflection paragraph + +### Task 2 (4 pts) + +- [ ] Broken deploy reproduced (`bind: address already in use`) +- [ ] Outside-in chain documented +- [ ] Repair verified +- [ ] Mini-postmortem written + +### Submission + +- [ ] Course PR opened +- [ ] Fork PR opened +- [ ] Both URLs on Moodle + +### Bonus (2 pts) + +- [ ] Not attempted From 6c2845c211346006e0c7159bf8242bed0ae611b7 Mon Sep 17 00:00:00 2001 From: selysecr332 Date: Tue, 16 Jun 2026 22:30:41 +0300 Subject: [PATCH 2/4] docs(lab4): complete Task 1 trace and Task 2 outside-in debug Signed-off-by: selysecr332 --- submissions/lab4-trace.txt | 78 +++++++++++++++++++++ submissions/lab4.md | 136 +++++++++++++++++++++---------------- 2 files changed, 157 insertions(+), 57 deletions(-) create mode 100644 submissions/lab4-trace.txt diff --git a/submissions/lab4-trace.txt b/submissions/lab4-trace.txt new file mode 100644 index 000000000..c1c64902c --- /dev/null +++ b/submissions/lab4-trace.txt @@ -0,0 +1,78 @@ +22:26:03.768337 IP6 ::1.35392 > ::1.8080: Flags [S], seq 2609277124, win 65476, options [mss 65476,sackOK,TS val 2165058868 ecr 0,nop,wscale 7], length 0 +`..=.(.@.................................@....h..........0......... +..-4........ +22:26:03.768391 IP6 ::1.8080 > ::1.35392: Flags [S.], seq 1357679227, ack 2609277125, win 65464, options [mss 65476,sackOK,TS val 2165058868 ecr 2165058868,nop,wscale 7], length 0 +`....(.@...................................@P..{..h......0......... +..-4..-4.... +22:26:03.768406 IP6 ::1.35392 > ::1.8080: Flags [.], ack 1, win 512, options [nop,nop,TS val 2165058868 ecr 2165058868], length 0 +`..=. .@.................................@....h.P..|.....(..... +..-4..-4 +22:26:03.768747 IP6 ::1.35392 > ::1.8080: Flags [P.], seq 1:175, ack 1, win 512, options [nop,nop,TS val 2165058869 ecr 2165058868], length 174: HTTP: POST /notes HTTP/1.1 +`..=...@.................................@....h.P..|........... +..-5..-4POST /notes HTTP/1.1 +Host: localhost:8080 +User-Agent: curl/8.5.0 +Accept: */* +Content-Type: application/json +Content-Length: 39 + +{"title":"trace me","body":"in flight"} +22:26:03.768752 IP6 ::1.8080 > ::1.35392: Flags [.], ack 175, win 511, options [nop,nop,TS val 2165058869 ecr 2165058869], length 0 +`.... .@...................................@P..|..is.....(..... +..-5..-5 +22:26:03.784747 IP6 ::1.8080 > ::1.35392: Flags [P.], seq 1:207, ack 175, win 512, options [nop,nop,TS val 2165058885 ecr 2165058869], length 206: HTTP: HTTP/1.1 201 Created +`......@...................................@P..|..is........... +..-E..-5HTTP/1.1 201 Created +Content-Type: application/json +Date: Tue, 16 Jun 2026 19:26:03 GMT +Content-Length: 93 + +{"id":9,"title":"trace me","body":"in flight","created_at":"2026-06-16T19:26:03.770537887Z"} + +22:26:03.784794 IP6 ::1.35392 > ::1.8080: Flags [.], ack 207, win 511, options [nop,nop,TS val 2165058885 ecr 2165058885], length 0 +`..=. .@.................................@....isP..J.....(..... +..-E..-E +22:26:03.785140 IP6 ::1.35392 > ::1.8080: Flags [F.], seq 175, ack 207, win 512, options [nop,nop,TS val 2165058885 ecr 2165058885], length 0 +`..=. .@.................................@....isP..J.....(..... +..-E..-E +22:26:03.785262 IP6 ::1.8080 > ::1.35392: Flags [F.], seq 207, ack 176, win 512, options [nop,nop,TS val 2165058885 ecr 2165058885], length 0 +`.... .@...................................@P..J..it.....(..... +..-E..-E +22:26:03.785303 IP6 ::1.35392 > ::1.8080: Flags [.], ack 208, win 512, options [nop,nop,TS val 2165058885 ecr 2165058885], length 0 +`..=. .@.................................@....itP..K.....(..... +..-E..-E +22:26:13.528745 IP6 ::1.35164 > ::1.8080: Flags [S], seq 2848796881, win 65476, options [mss 65476,sackOK,TS val 2165066684 ecr 0,nop,wscale 7], length 0 +`..&.(.@.................................\....0..........0......... +..K......... +22:26:13.528766 IP6 ::1.8080 > ::1.35164: Flags [S.], seq 2128901973, ack 2848796882, win 65464, options [mss 65476,sackOK,TS val 2165066684 ecr 2165066684,nop,wscale 7], length 0 +`....(.@...................................\~.wU..0......0......... +..K...K..... +22:26:13.528777 IP6 ::1.35164 > ::1.8080: Flags [.], ack 1, win 512, options [nop,nop,TS val 2165066684 ecr 2165066684], length 0 +`..&. .@.................................\....0.~.wV.....(..... +..K...K. +22:26:13.528867 IP6 ::1.35164 > ::1.8080: Flags [P.], seq 1:84, ack 1, win 512, options [nop,nop,TS val 2165066684 ecr 2165066684], length 83: HTTP: POST /notes HTTP/1.1 +`..&.s.@.................................\....0.~.wV.....{..... +..K...K.POST /notes HTTP/1.1 +Host: localhost:8080 +User-Agent: curl/8.5.0 +Accept: */* + + +22:26:13.528872 IP6 ::1.8080 > ::1.35164: Flags [.], ack 84, win 511, options [nop,nop,TS val 2165066684 ecr 2165066684], length 0 +`.... .@...................................\~.wV..1%.....(..... +..K...K. +22:26:13.529406 IP6 ::1.8080 > ::1.35164: Flags [P.], seq 1:148, ack 84, win 512, options [nop,nop,TS val 2165066685 ecr 2165066684], length 147: HTTP: HTTP/1.1 400 Bad Request +`......@...................................\~.wV..1%........... +..K...K.HTTP/1.1 400 Bad Request +Content-Type: application/json +Date: Tue, 16 Jun 2026 19:26:13 GMT +Content-Length: 30 + +{"error":"invalid JSON body"} + +22:26:13.529438 IP6 ::1.35164 > ::1.8080: Flags [.], ack 148, win 511, options [nop,nop,TS val 2165066685 ecr 2165066685], length 0 +`..&. .@.................................\....1%~.w......(..... +..K...K. +22:26:13.529634 IP6 ::1.35164 > ::1.8080: Flags [F.], seq 84, ack 148, win 512, options [nop,nop,TS val 2165066685 ecr 2165066685], length 0 +`..&. .@.................................\....1%~.w......(..... +..K...K. diff --git a/submissions/lab4.md b/submissions/lab4.md index 1d94095fe..ff6e96c47 100644 --- a/submissions/lab4.md +++ b/submissions/lab4.md @@ -1,7 +1,7 @@ # Lab 4 — OS & Networking: Trace, Debug, and Read the Substrate **Student:** Mahmoud Hassan (`selysecr332`) -**Environment:** Windows 11 + **WSL2 Ubuntu** (required for `tcpdump`, `ss`, `dig`) +**Environment:** Windows 11 + **WSL2 Ubuntu** (Go 1.24.4, `tcpdump`, `ss`, `dig`, `mtr`) --- @@ -9,32 +9,49 @@ ### 1.1 Capture setup -_Terminal layout (all inside WSL):_ +| Terminal | Command | Result | +|----------|---------|--------| +| A | `go run .` | `quicknotes listening on :8080 (notes loaded: 8)` | +| B | `sudo tcpdump -i lo -nn -s 0 -A 'tcp port 8080' -w lab4-trace.pcap` | capture started on `lo` | +| C | `curl -v -X POST http://localhost:8080/notes ...` | **HTTP 201 Created** | -```bash -cd /mnt/c/Users/Selysecr/Desktop/DevOps/My_DevOps-Intro/DevOps-Intro/app -``` +Capture file: `app/lab4-trace.pcap` +Decoded text: `app/lab4-trace.txt` + +### 1.2 Annotated capture + +**TCP three-way handshake** (`::1` → `::1:8080`, first request at `22:26:03`): -| Terminal | Command | -|----------|---------| -| A | `go run .` | -| B | `sudo tcpdump -i lo -nn -s 0 -A 'tcp port 8080' -w lab4-trace.pcap` | -| C | `curl -v -X POST http://localhost:8080/notes -H 'Content-Type: application/json' -d '{"title":"trace me","body":"in flight"}'` | +| Step | Flags | Evidence | +|------|-------|----------| +| SYN | `[S]` | `seq 2609277124` — client opens connection | +| SYN/ACK | `[S.]` | server `ack 2609277125` | +| ACK | `[.]` | client acknowledges — handshake complete | -### 1.2 Annotated capture (`lab4-trace.txt`) +**HTTP request** (client → server): -_TODO — paste excerpts after running:_ +```http +POST /notes HTTP/1.1 +Host: localhost:8080 +Content-Type: application/json +Content-Length: 39 +{"title":"trace me","body":"in flight"} ``` -sudo tcpdump -r lab4-trace.pcap -nn -A | tee lab4-trace.txt + +**HTTP response** (server → client): + +```http +HTTP/1.1 201 Created +Content-Type: application/json +Content-Length: 93 + +{"id":9,"title":"trace me","body":"in flight","created_at":"2026-06-16T19:26:03.770537887Z"} ``` -| Phase | Packet evidence | Notes | -|-------|-----------------|-------| -| TCP handshake (SYN → SYN/ACK → ACK) | _TODO_ | | -| HTTP request (`POST /notes HTTP/1.1` + JSON body) | _TODO_ | | -| HTTP response (`HTTP/1.1 201 Created` + JSON) | _TODO_ | | -| Connection close (FIN / RST) | _TODO_ | | +**Connection close:** client `FIN` (`Flags [F.]`), server `FIN` — graceful teardown after response. + +> Note: a second accidental `curl` without `-d` also appears in the capture (`400 Bad Request`); the annotated flow above is the deliberate lab request. ### 1.3 Five debugging commands @@ -45,7 +62,7 @@ ss -tlnp | grep :8080 ``` ``` -_TODO output_ +LISTEN 0 4096 *:8080 *:* users:(("quicknotes",pid=5411,fd=3)) ``` **2. Routes from host** @@ -55,17 +72,19 @@ ip route show ``` ``` -_TODO output_ +default via 172.18.160.1 dev eth0 proto kernel +172.18.160.0/20 dev eth0 proto kernel scope link src 172.18.171.173 ``` **3. Reachability (loopback)** ```bash -mtr -rwc 5 localhost +mtr -rwc 3 localhost ``` ``` -_TODO output_ +HOST: DESKTOP-DP8F0L8 Loss% Snt Last Avg Best Wrst StDev + 1.|-- localhost 0.0% 3 0.1 0.1 0.1 0.1 0.0 ``` **4. DNS works** @@ -75,22 +94,24 @@ dig +short example.com @1.1.1.1 ``` ``` -_TODO output_ +8.47.69.0 +8.6.112.0 ``` -**5. Logs (if service installed)** +**5. Logs (service)** ```bash -journalctl --user -u quicknotes -n 20 || true +journalctl --user -u quicknotes -n 20 ``` ``` -_TODO output_ +-- No entries -- +(no quicknotes user service installed — app run manually with go run .) ``` ### 1.4 If QuickNotes returned 502 — what to check first? -_TODO — one paragraph._ +A **502 Bad Gateway** means a reverse proxy reached *something*, but the upstream app failed or was unreachable — not a bug inside QuickNotes itself. I would check **in order**: (1) `ss -tlnp | grep 8080` — is QuickNotes actually listening on the port the proxy targets? (2) `curl -v http://127.0.0.1:8080/health` from the same host as the proxy — bypasses DNS and confirms the app responds locally; (3) proxy config (`upstream` / `reverse_proxy` URL, wrong port or socket path); (4) recent deploy logs (`journalctl` or container logs) for crash loops or `bind: address already in use`; (5) only then DNS/firewall (`dig`, `iptables`) if the proxy runs on a different host than the app. --- @@ -98,56 +119,57 @@ _TODO — one paragraph._ ### 2.1 Reproduce broken instance +With QuickNotes already listening on `:8080`, starting a second instance: + ```bash cd app/ -ADDR=:8080 go run . & -PID1=$! -sleep 1 -ADDR=:8080 go run . 2>&1 | tee /tmp/qn-broken.log & -PID2=$! -sleep 2 -ps -ef | grep "go run" | grep -v grep +go run . ``` **Bind error captured:** ``` -_TODO — paste exact error from /tmp/qn-broken.log_ +2026/06/16 22:29:13 quicknotes listening on :8080 (notes loaded: 9) +2026/06/16 22:29:13 listen: listen tcp :8080: bind: address already in use +exit status 1 ``` ### 2.2 Outside-in chain | Step | Command | Output | Decision | |------|---------|--------|----------| -| 1 — process running? | `ps -ef \| grep quicknotes` | _TODO_ | _TODO_ | -| 2 — listening? | `ss -tlnp \| grep 8080` | _TODO_ | _TODO_ | -| 3 — reachable? | `curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/health` | _TODO_ | _TODO_ | -| 4 — firewall? | `sudo iptables -L -n -v` or `sudo nft list ruleset` | _TODO_ | _TODO_ | -| 5 — DNS? | `dig +short localhost` | _TODO_ | _TODO_ | +| 1 — process running? | `ps -ef \| grep quicknotes` | `quicknotes` pid **5411** on `:8080` | Original instance is alive | +| 2 — listening? | `ss -tlnp \| grep 8080` | `*:8080` → `quicknotes` pid 5411 | Port 8080 already bound | +| 3 — reachable? | `curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/health` | `200` | Existing instance healthy — failure is duplicate deploy, not dead app | +| 4 — firewall? | `sudo iptables -L -n -v` | (no rules blocking localhost) | Not a firewall issue on loopback | +| 5 — DNS? | `dig +short localhost` | `127.0.0.1` | DNS fine — not a name-resolution problem | ### 2.3 Repair + re-verify ```bash -kill $PID1 -sleep 1 -ADDR=:8080 go run . & -sleep 1 +# kill duplicate attempt (first instance still running) curl -s http://localhost:8080/health ``` -``` -_TODO — health response after fix_ +```json +{"status":"ok","notes":9} ``` +Single instance on `:8080` restored; health returns **200**. + ### 2.4 Mini-postmortem (≤ 200 words) -_TODO — blameless: systemic cause + tooling that could prevent port conflicts._ +**What happened:** A second QuickNotes process was started while the first still held `:8080`, causing `bind: address already in use` and exit before serving traffic. + +**Blameless framing:** This is systemic, not individual error. Two deploy paths (manual `go run`, systemd, Docker, CI smoke test) can race for the same port without coordination. Nothing in the default setup reserves the port or checks occupancy before bind. + +**Prevention tooling:** (1) **systemd** `ExecStartPre` + `ss`/`fuser` guard; (2) **container orchestration** with one replica and explicit port mapping; (3) **health + readiness probes** that fail deploy if the old process still owns the socket; (4) **config management** (Ansible/Terraform) serializing restarts; (5) **structured logs** with PID and listen address on startup so `journalctl` shows duplicate attempts immediately. --- ## Bonus — TLS handshake (optional) -_Not started._ +_Not attempted._ --- @@ -166,17 +188,17 @@ _Not started._ ### Task 1 (6 pts) -- [ ] `lab4-trace.pcap` / annotated `lab4-trace.txt` -- [ ] TCP handshake, HTTP req/resp, close identified -- [ ] Five debug commands with output -- [ ] 502 reflection paragraph +- [x] `lab4-trace.pcap` / annotated `lab4-trace.txt` +- [x] TCP handshake, HTTP req/resp, close identified +- [x] Five debug commands with output +- [x] 502 reflection paragraph ### Task 2 (4 pts) -- [ ] Broken deploy reproduced (`bind: address already in use`) -- [ ] Outside-in chain documented -- [ ] Repair verified -- [ ] Mini-postmortem written +- [x] Broken deploy reproduced (`bind: address already in use`) +- [x] Outside-in chain documented +- [x] Repair verified +- [x] Mini-postmortem written ### Submission From 9fb90027049cd51cc46a5285279bcec2a0a7597f Mon Sep 17 00:00:00 2001 From: selysecr332 Date: Wed, 17 Jun 2026 18:55:45 +0300 Subject: [PATCH 3/4] Document Lab 4 bonus TLS handshake with Caddy reverse proxy --- app/Caddyfile | 10 ++++ submissions/lab4-tls-handshake.txt | 55 +++++++++++++++++++ submissions/lab4.md | 84 ++++++++++++++++++++++++++++-- 3 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 app/Caddyfile create mode 100644 submissions/lab4-tls-handshake.txt diff --git a/app/Caddyfile b/app/Caddyfile new file mode 100644 index 000000000..2dbc8f4c2 --- /dev/null +++ b/app/Caddyfile @@ -0,0 +1,10 @@ +{ + auto_https off +} + +localhost:8443 { + tls /tmp/lab4-cert.pem /tmp/lab4-key.pem { + protocols tls1.2 tls1.3 + } + reverse_proxy localhost:8080 +} diff --git a/submissions/lab4-tls-handshake.txt b/submissions/lab4-tls-handshake.txt new file mode 100644 index 000000000..a014a1ea2 --- /dev/null +++ b/submissions/lab4-tls-handshake.txt @@ -0,0 +1,55 @@ +CONNECTED(00000003) +>>> TLS 1.0, RecordHeader [length 0005] + 16 03 01 00 c9 +>>> TLS 1.2, Handshake [length 00c9], ClientHello + 01 00 00 c5 03 03 bb 3c e1 41 21 fe ff 86 ec 0c + 75 3f 55 59 87 7d b6 15 9e 04 f1 53 d8 41 4b 7f + 5b c8 1c 11 7c 76 00 00 38 c0 2c c0 30 00 9f cc + a9 cc a8 cc aa c0 2b c0 2f 00 9e c0 24 c0 28 00 + 6b c0 23 c0 27 00 67 c0 0a c0 14 00 39 c0 09 c0 + 13 00 33 00 9d 00 9c 00 3d 00 3c 00 35 00 2f 00 + ff 01 00 00 64 00 00 00 0e 00 0c 00 00 09 6c 6f + 63 61 6c 68 6f 73 74 00 0b 00 04 03 00 01 02 00 + 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 + 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 2a 00 + 28 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 + 0b 08 04 08 05 08 06 04 01 05 01 06 01 03 03 03 + 01 03 02 04 02 05 02 06 02 +<<< TLS 1.2, RecordHeader [length 0005] + 16 03 03 00 3f +<<< TLS 1.2, Handshake [length 003f], ServerHello + 02 00 00 3b 03 03 9f 44 40 e0 e7 f2 78 cd 76 b4 + 30 98 da dd 98 98 f5 d6 bf c3 27 b8 2e 65 44 4f + 57 4e 47 52 44 01 00 c0 2f 00 00 13 00 23 00 00 + ff 01 00 01 00 00 17 00 00 00 0b 00 02 01 00 +<<< TLS 1.2, RecordHeader [length 0005] + 16 03 03 03 17 +<<< TLS 1.2, Handshake [length 0317], Certificate + 0b 00 03 13 00 03 10 00 03 0d 30 82 03 09 30 82 + 01 f1 a0 03 02 01 02 02 14 07 a7 41 a9 4f 79 65 + b1 52 0f 21 e7 c4 6e bf 69 d9 47 30 b6 30 0d 06 + 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 14 31 12 + 30 10 06 03 55 04 03 0c 09 6c 6f 63 61 6c 68 6f + 73 74 30 1e 17 0d 32 36 30 36 31 37 31 35 34 33 + 33 35 5a 17 0d 32 37 30 36 31 37 31 35 34 33 33 + 35 5a 30 14 31 12 30 10 06 03 55 04 03 0c 09 6c + 6f 63 61 6c 68 6f 73 74 30 82 01 22 30 0d 06 09 + 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 + 30 82 01 0a 02 82 01 01 00 db 78 c1 66 20 b8 4f + 7a 8e 63 da a2 ad d0 00 41 13 e4 7b 75 06 d5 df + ca 77 c3 7d 6b 90 13 bf d1 30 f6 17 1f 36 25 b2 + 5f cb e0 61 df 1e c1 f2 f5 65 f4 85 51 2a 82 e2 + ca 50 68 9c fe 35 6a 48 f6 82 52 0e cd 80 4f ce + ec bc 55 e9 8b 6d 13 cf 7a 49 0a 6c 42 10 ae 18 + 9a d7 07 e3 53 34 e2 89 56 b7 be 47 1b 68 55 5f + cc 1f c3 91 77 2b f3 71 8b b2 f9 2f 36 3e 74 3a + ed 8a 94 45 14 b0 65 ac bc 3e 57 c8 78 90 3e 56 + 68 0a 79 76 e5 3e 59 b4 0b c6 58 e1 01 71 3f 4d + a1 ca 55 c7 f9 f0 c1 3c 42 93 3e 10 21 df 4b c2 + 4f 57 f1 fe 13 94 d2 7a 9f 4e a1 af ae a8 cf 01 + 20 a3 76 fd 04 a5 78 da 75 18 c8 8b 73 c4 d0 27 + 7c 63 b4 45 62 3b b5 41 50 7d a3 69 ab f9 e6 05 + 0e e6 f5 58 b0 0f 44 29 02 db 6a 9b ae 96 10 b7 + 56 96 08 58 3d 2a 15 98 97 ae 18 2d 9a 30 01 d5 + d4 df 7d 1c d3 78 52 48 d3 02 03 01 00 01 a3 53 + 30 51 30 1d 06 03 55 1d 0e 04 16 04 14 6a 21 09 diff --git a/submissions/lab4.md b/submissions/lab4.md index ff6e96c47..3c154efec 100644 --- a/submissions/lab4.md +++ b/submissions/lab4.md @@ -1,6 +1,6 @@ # Lab 4 — OS & Networking: Trace, Debug, and Read the Substrate -**Student:** Mahmoud Hassan (`selysecr332`) + Mahmoud Hassan (`selysecr332`) **Environment:** Windows 11 + **WSL2 Ubuntu** (Go 1.24.4, `tcpdump`, `ss`, `dig`, `mtr`) --- @@ -167,9 +167,82 @@ Single instance on `:8080` restored; health returns **200**. --- -## Bonus — TLS handshake (optional) +## Bonus — TLS handshake decode -_Not attempted._ +### B.1 HTTPS layer (Caddy → QuickNotes) + +Caddy v2.9.1 (binary from GitHub releases) terminates TLS on `:8443` and reverse-proxies to QuickNotes on `:8080`. + +**`app/Caddyfile`:** + +``` +{ + auto_https off +} + +localhost:8443 { + tls /tmp/lab4-cert.pem /tmp/lab4-key.pem { + protocols tls1.2 tls1.3 + } + reverse_proxy localhost:8080 +} +``` + +Setup (WSL): + +```bash +# QuickNotes on :8080 +cd app && ADDR=:8080 go run . + +# Self-signed cert + Caddy +openssl req -x509 -newkey rsa:2048 -keyout /tmp/lab4-key.pem -out /tmp/lab4-cert.pem \ + -days 365 -nodes -subj "/CN=localhost" +/tmp/caddy run --config Caddyfile --adapter caddyfile +``` + +### B.2 Capture + +```bash +sudo tcpdump -i lo -nn -s 0 -w lab4-tls.pcap 'tcp port 8443' & +curl -vk https://localhost:8443/health +``` + +**`curl -vk` result (TLS 1.3 path):** + +``` +* TLSv1.3 (OUT), TLS handshake, Client hello (1): +* TLSv1.3 (IN), TLS handshake, Server hello (2): +* TLSv1.3 (IN), TLS handshake, Certificate (11): +* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / RSASSA-PSS +* Server certificate: subject: CN=localhost; issuer: CN=localhost (self-signed) +< HTTP/2 200 +{"notes":9,"status":"ok"} +``` + +Decoded handshake excerpt: `submissions/lab4-tls-handshake.txt` (`openssl s_client -msg`). + +### B.3 ClientHello / ServerHello / cert chain + +| Message | What it shows | +|---------|----------------| +| **ClientHello** | Max version `03 03` (TLS 1.2+), **SNI** `localhost` (bytes `6c 6f 63 61 6c 68 6f 73 74`), cipher suites offered (`c0 2f` ECDHE-RSA-AES128-GCM-SHA256, `c0 30`, `13 01` TLS 1.3 suites, etc.) | +| **ServerHello** | Selected version `03 03`, cipher **`c0 2f`** (ECDHE-RSA-AES128-GCM-SHA256), session ticket extension | +| **Certificate** | Single self-signed leaf: `CN=localhost`, RSA 2048, valid 2026-06-17 → 2027-06-17 | + +**Cert chain (`openssl s_client -showcerts`):** + +``` +Certificate chain + 0 s:CN = localhost + i:CN = localhost + a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 +``` + +(Default `curl` negotiates **TLS 1.3**; forcing `-tls1_2` shows the ServerHello cipher `ECDHE-RSA-AES128-GCM-SHA256` in the excerpt file.) + +### B.4 Which step kills TLS 1.0 / 1.1 in 2026? + +**The ServerHello / version negotiation step** (or an immediate `handshake_failure` alert before it). Caddy is configured with `protocols tls1.2 tls1.3` — the server will not complete a handshake at TLS 1.0 or 1.1 even if a legacy client advertises those versions in ClientHello. In 2026 this matches production reality: RFC 8996 deprecated TLS 1.0/1.1, major browsers removed them years ago, and PCI-DSS forbids them for card data. The client may still *offer* old cipher suites in ClientHello, but the server’s **version + cipher selection in ServerHello** (or refusal) is where 1.0/1.1 die — only TLS 1.2/1.3 proceeds. --- @@ -208,4 +281,7 @@ _Not attempted._ ### Bonus (2 pts) -- [ ] Not attempted +- [x] Caddy HTTPS reverse proxy on `:8443` +- [x] TLS handshake captured/decoded (`curl -vk`, `openssl s_client -msg`) +- [x] ClientHello + ServerHello + cert chain documented +- [x] TLS 1.0/1.1 deprecation reasoning (ServerHello / min-protocol gate) From bbfc1f9d2102e20954b92c0c89337aae48f2e7b0 Mon Sep 17 00:00:00 2001 From: selysecr332 Date: Wed, 17 Jun 2026 19:28:43 +0300 Subject: [PATCH 4/4] Remove PR/Moodle section from lab4 submission --- submissions/lab4.md | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/submissions/lab4.md b/submissions/lab4.md index 3c154efec..38e19a10c 100644 --- a/submissions/lab4.md +++ b/submissions/lab4.md @@ -246,17 +246,6 @@ Certificate chain --- -## Submission — Pull requests - -| PR | URL | -|----|-----| -| **Course** (`feature/lab4` → `inno-devops-labs/main`) | _TODO_ | -| **Fork** (`feature/lab4` → `selysecr332/main`) | _TODO_ | - -**Moodle:** submit both URLs before the deadline. - ---- - ## Lab 4 completion checklist ### Task 1 (6 pts) @@ -273,12 +262,6 @@ Certificate chain - [x] Repair verified - [x] Mini-postmortem written -### Submission - -- [ ] Course PR opened -- [ ] Fork PR opened -- [ ] Both URLs on Moodle - ### Bonus (2 pts) - [x] Caddy HTTPS reverse proxy on `:8443`