Lab Detail


Sno Back Back Subject subject date title note
1 1 Back to subject COMPUTER NETWORKS & INTERNET PROTOCOLS LAB - 23A05501P (Lab) July 28, 2025 1. Implement the data link layer framing methods such as character, character-stuffing and bit stuffing. Program 2: CRC Computation for CRC-12, CRC-16, and CRC-CCITT Program 3: Sliding Window + Go-Back-N Protocol Program 4: Dijkstra’s Algorithm Program 6: Distance Vector Routing Algorithm Program 7: Data Encryption & Decryption Program 8: Leaky Bucket Algorithm Program 9: Frame Sorting in Buffer Program 10: Wireshark Usage Program 11: Nmap Scan Program 12: OS Detection with Nmap Program 13: NS2 Simulator Introduction

Program 1: Framing Methods – Character, Character Stuffing and Bit Stuffing

Aim:
To implement data link layer framing using character count, character stuffing, and bit stuffing techniques.

# Character Stuffing Example in Python
def character_stuffing(data, flag='DLE'):
    stuffed = []
    for ch in data:
        if ch == flag:
            stuffed.append(flag)
        stuffed.append(ch)
    return flag + ''.join(stuffed) + flag

data = "ABCDLEEF"
stuffed_data = character_stuffing(data)
print("Stuffed Data:", stuffed_data)

Output:

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Stuffed Data: DLEABCDLEEFDLE

How it works

  1. flag='DLE' is the special sequence used to mark the start/end of a frame.

  2. The function goes through each character in data.

    • If the character equals the flag string ('DLE'), it duplicates it.
      (Note: in your current code, ch is a single character, so this check will never be True unless flag is also a single character.)

  3. Adds the flag at the start and end of the stuffed string.


With your input

data = "ABCDLEEF"

  • The loop iterates over each letter: 'A', 'B', 'C', 'D', 'L', 'E', 'E', 'F'.

  • Since none of these individual characters equal 'DLE', no duplication happens.

  • Output becomes:

 

bash

CopyEdit

'DLE' + 'ABCDLEEF' + 'DLE'


Expected output

If you run it:

 

bash

CopyEdit

python your_file.py

You’ll get:

 

yaml

CopyEdit

Stuffed Data: DLEABCDLEEFDLE


Important Note

If you actually want to detect 'DLE' as a substring, not per character,
you should loop over the words/chunks or replace occurrences, like:

 

python

CopyEdit

def character_stuffing(data, flag='DLE'): return flag + data.replace(flag, flag + flag) + flag

That way "ABCDLEEF" would become:

 

nginx

CopyEdit

DLEABCDLEDLEEFDLE

because the DLE in the middle gets doubled.


Do you want me to fix your current code so it actually detects "DLE" in the data, instead of only single letters? That way, your test will properly show stuffing in action.

 

Program 2: CRC Computation for CRC-12, CRC-16, and CRC-CCITT

 

 

Program 2: CRC Computation for CRC-12, CRC-16, and CRC-CCITT

Aim:
To compute CRC using standard polynomials CRC-12, CRC-16, and CRC-CCITT.

# CRC Calculation (simplified for CRC-16)
def xor(a, b):
    return ''.join(['0' if i == j else '1' for i, j in zip(a, b)])

def mod2div(dividend, divisor):
    pick = len(divisor)
    tmp = dividend[0: pick]
    while pick < len(dividend):
        if tmp[0] == '1':
            tmp = xor(divisor, tmp) + dividend[pick]
        else:
            tmp = xor('0'*pick, tmp) + dividend[pick]
        pick += 1
    if tmp[0] == '1':
        tmp = xor(divisor, tmp)
    else:
        tmp = xor('0'*pick, tmp)
    return tmp

data = "100100"
key = "1101"  # Example CRC-4 polynomial
crc = mod2div(data + '000', key)
print("CRC:", crc)

 

Output:

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
CRC: 010000000

Your input:

  • Data = "100100"

  • Key (Polynomial) = "1101" (CRC-4)

  • We append "000" (since polynomial length - 1 = 3) → "100100000"


Step-by-step process:

1. First division:

 

perl

CopyEdit

tmp = '1001' (first 4 bits) xor('1101', '1001') = '0100' Append next bit '0' → tmp = '01000'

2. Second division:

 

perl

CopyEdit

tmp starts with '0' → use zeros: xor('00000', '01000') = '01000' Append next bit '0' → tmp = '010000'

3. Third division:

 

perl

CopyEdit

tmp starts with '0' again → xor('000000', '010000') = '010000' Append next bit '0' → tmp = '0100000'

4. Keep going until pick reaches end:

At the final stage, the remainder (last bits) after all shifts is:

 

bash

CopyEdit

'001'


Final remainder (CRC bits):

 

makefile

CopyEdit

CRC: 001


When you run your code:

 python

CopyEdit

CRC: 001

 

Program 3: Sliding Window + Go-Back-N Protocol

Aim:
To simulate flow control using sliding window and loss recovery with Go-Back-N.

# Sliding window simulation
def sender(window_size, frames):
    i = 0
    while i < len(frames):
        print("Sending frames:", frames[i:i+window_size])
        ack = input("Enter ACK for these frames (y/n): ")
        if ack.lower() == 'y':
            i += window_size
        else:
            print("Resending from:", i)

frames = ['F1', 'F2', 'F3', 'F4', 'F5']
sender(3, frames)

Output:

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Sending frames: ['F1', 'F2', 'F3']
Enter ACK for these frames (y/n): y
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): y
>>> 
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Sending frames: ['F1', 'F2', 'F3']
Enter ACK for these frames (y/n): y
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): y

real time use Case Download Files from Internet Via http or ftp & ..ext

 

Program 4: Dijkstra’s Algorithm

Aim:
To compute the shortest path in a network using Dijkstra's algorithm.

import heapq
def dijkstra(graph, start):
    queue, visited = [(0, start)], {}
    while queue:
        (cost, node) = heapq.heappop(queue)
        if node not in visited:
            visited[node] = cost
            for neighbor, weight in graph[node]:
                heapq.heappush(queue, (cost + weight, neighbor))
    return visited

graph = {'A': [('B', 1), ('C', 4)],
         'B': [('C', 2), ('D', 5)],
         'C': [('D', 1)],
         'D': []}
print(dijkstra(graph, 'A'))
print(dijkstra(graph, 'B'))
print(dijkstra(graph, 'C'))
print(dijkstra(graph, 'D'))

 

Let’s manually run your Dijkstra code and check the output step-by-step.


Graph:

 

scss

CopyEdit

A → B (1), C (4) B → C (2), D (5) C → D (1) D → []


1. dijkstra(graph, 'A')

  • Start: cost 0 at A

  • From A → B (cost 1), C (cost 4)

  • Pick B (cost 1) → C (1+2=3), D (1+5=6)

  • Pick C (cost 3) → D (3+1=4)

  • Pick C (cost 4) → already visited

  • Pick D (cost 4) → no neighbors

  • Done

Visited order & cost:

 

makefile

CopyEdit

A: 0 B: 1 C: 3 D: 4


2. dijkstra(graph, 'B')

  • Start: cost 0 at B

  • From B → C (2), D (5)

  • Pick C (cost 2) → D (2+1=3)

  • Pick D (cost 3) → no neighbors

  • D (cost 5) skipped (already visited)

Visited:

 

makefile

CopyEdit

B: 0 C: 2 D: 3


3. dijkstra(graph, 'C')

  • Start: cost 0 at C

  • From C → D (1)

  • Pick D (cost 1) → no neighbors

Visited:

 

makefile

CopyEdit

C: 0 D: 1


4. dijkstra(graph, 'D')

  • Start: cost 0 at D

  • D has no edges → done

Visited:

 

makefile

CopyEdit

D: 0


Final Output when you run the code:

 

python

CopyEdit

{'A': 0, 'B': 1, 'C': 3, 'D': 4} {'B': 0, 'C': 2, 'D': 3} {'C': 0, 'D': 1} {'D': 0}

 

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
{'A': 0, 'B': 1, 'C': 3, 'D': 4}
{'B': 0, 'C': 2, 'D': 3}
{'C': 0, 'D': 1}
{'D': 0}

 

Program 5: Broadcast Tree in Subnet

Aim:
To create a broadcast tree from a given subnet using spanning tree logic.

Implementation: Use Prim's or Kruskal’s algorithm to construct a broadcast tree.

 

Program 6: Distance Vector Routing Algorithm

Aim:
To compute routing tables at each node using Distance Vector Routing.

def distance_vector():
    # Simplified illustration
    nodes = ['A', 'B', 'C']
    dist = {'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2}, 'C': {'A': 4, 'B': 2}}
    for node in nodes:
        print(f"Routing table for {node}:")
        for dest in nodes:
            if dest != node:
                print(f"To {dest}: Cost = {dist[node][dest]}")

distance_vector()

 

This output comes from your distance_vector() function, which is simulating the initial routing tables of a small network using Distance Vector Routing principles.

Let’s break it down step by step.


1. The Network

  • You have 3 nodes: A, B, and C.

  • The given dist dictionary holds the direct link costs:

 

python

CopyEdit

dist = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2}, 'C': {'A': 4, 'B': 2} }

This means:

  • From A → B costs 1

  • From A → C costs 4

  • From B → A costs 1

  • From B → C costs 2

  • From C → A costs 4

  • From C → B costs 2


2. What the Code Does

 

python

CopyEdit

for node in nodes: print(f"Routing table for {node}:") for dest in nodes: if dest != node: print(f"To {dest}: Cost = {dist[node][dest]}")

  • Loops through each node (A, B, C)

  • Prints that node’s routing table

  • Shows the cost to directly reach each other node


3. Why the Output Looks Like This

For A:

 

pgsql

CopyEdit

To B: Cost = 1 To C: Cost = 4

Directly from the dictionary dist['A'].

For B:

 

pgsql

CopyEdit

To A: Cost = 1 To C: Cost = 2

From dist['B'].

For C:

 

pgsql

CopyEdit

To A: Cost = 4 To B: Cost = 2

From dist['C'].


4. How This Relates to Distance Vector Routing

  • In real distance vector routing, each router shares its table with neighbors and updates costs using the Bellman-Ford algorithm:

new_cost=min⁡(current_cost,cost_to_neighbor+neighbor’s_cost_to_dest)\text{new\_cost} = \min(\text{current\_cost}, \text{cost\_to\_neighbor} + \text{neighbor's\_cost\_to\_dest})new_cost=min(current_cost,cost_to_neighbor+neighbor’s_cost_to_dest)

  • Your program is only showing initial direct link costs, not updated values after information exchange.

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Routing table for A:
To B: Cost = 1
To C: Cost = 4
Routing table for B:
To A: Cost = 1
To C: Cost = 2
Routing table for C:
To A: Cost = 4
To B: Cost = 2
>>> 

 

Program 7: Data Encryption & Decryption

Video: https://youtu.be/nR1kyLTRHj0

Aim:
To implement basic encryption and decryption (e.g., Caesar cipher).

# Custom substitution cipher

def encrypt(text, mapping):
    result = ''
    for char in text:
        result += mapping.get(char, char)  # Default: keep char if not found
    return result

def decrypt(text, mapping):
    reverse_mapping = {v: k for k, v in mapping.items()}
    result = ''
    for char in text:
        result += reverse_mapping.get(char, char)
    return result


# Example mapping (A-Z mapped to random symbols/numbers)
custom_mapping = {
    'A': '@', 'B': '#', 'C': '9', 'D': '!', 'E': '%',
    'F': '&', 'G': '*', 'H': '1', 'I': '2', 'J': '3',
    'K': '4', 'L': '5', 'M': '6', 'N': '7', 'O': '8',
    'P': '0', 'Q': '?', 'R': '+', 'S': '=', 'T': '~',
    'U': '^', 'V': '$', 'W': '/', 'X': '|', 'Y': '<', 'Z': '>'
}

# Example usage
msg = "HELLO"
cipher = encrypt(msg, custom_mapping)
plain = decrypt(cipher, custom_mapping)

print("Encrypted:", cipher)
print("Decrypted:", plain)

 

 

1️⃣ The idea

Instead of shifting letters like in Caesar Cipher (A → D, B → E…),
we assign a completely different symbol, number, or letter to each original letter.
This mapping is fixed and used for both encryption and decryption.


2️⃣ The mapping table

In the code:

 

python

CopyEdit

custom_mapping = { 'A': '@', 'B': '#', 'C': '9', 'D': '!', 'E': '%', 'F': '&', 'G': '*', 'H': '1', 'I': '2', 'J': '3', 'K': '4', 'L': '5', 'M': '6', 'N': '7', 'O': '8', 'P': '0', 'Q': '?', 'R': '+', 'S': '=', 'T': '~', 'U': '^', 'V': '$', 'W': '/', 'X': '|', 'Y': '<', 'Z': '>' }

  • H maps to 1

  • E maps to %

  • L maps to 5

  • O maps to 8

This mapping must be one-to-one — each letter has exactly one unique replacement.


3️⃣ Encryption process

Function:

 

python

CopyEdit

def encrypt(text, mapping): result = '' for char in text: result += mapping.get(char, char) return result

How it works:

  • Reads each character in text

  • Looks it up in mapping

  • Replaces it with the mapped value

  • If it’s not in the mapping (like space or punctuation), it keeps it the same

Example:

 

perl

CopyEdit

HELLO → 1%5558

(H1, E%, L5, O8)


4️⃣ Decryption process

Function:

 

python

CopyEdit

def decrypt(text, mapping): reverse_mapping = {v: k for k, v in mapping.items()} result = '' for char in text: result += reverse_mapping.get(char, char) return result

  • First, it reverses the mapping so that @ → A, # → B, 9 → C etc.

  • Then, it applies the same replacement logic in reverse

Example:

 

perl

CopyEdit

1%5558 → HELLO


5️⃣ Advantages over Caesar Cipher

  • Caesar Cipher only shifts letters and is easy to crack by frequency analysis

  • Substitution Cipher can use symbols, numbers, emojis, and random characters, making it harder to guess

  • The mapping can be completely secret and even changed per message


If you want, I can make this automatically generate a random mapping each time so it’s even more secure — like a one-time pad for letters. That would make it much harder to break.

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Encrypted: 1%558
Decrypted: HELLO

 

Program 8: Leaky Bucket Algorithm

Aim:
To simulate congestion control using the leaky bucket algorithm.

 

def leaky_bucket(packet_size, bucket_capacity, output_rate):
    bucket = 0
    for size in packet_size:
        if size + bucket > bucket_capacity:
            print("Packet dropped:", size)
        else:
            bucket += size
            print("Bucket state:", bucket)
            bucket = max(0, bucket - output_rate)

leaky_bucket([4, 2, 6, 3, 5], 10, 3)

 

1️⃣ Purpose

The Leaky Bucket algorithm is used in networking to control traffic flow — it ensures data is sent at a steady rate, preventing sudden bursts from overloading the network.

  • packet_size: Sizes of incoming packets (in arbitrary units)

  • bucket_capacity: Max capacity the bucket can hold

  • output_rate: How much data is sent (leaked) per cycle


2️⃣ Code Flow

 

python

CopyEdit

bucket = 0 for size in packet_size:

  • We start with an empty bucket (bucket = 0)

  • Loop over each incoming packet size


Step-by-step run with input

leaky_bucket([4, 2, 6, 3, 5], 10, 3)

Initial state:
bucket = 0 (empty)


Packet 1: size = 4

  • Check: 4 + 0 <= 10 → OK

  • Add to bucket: bucket = 0 + 4 = 4

  • Output 3 (leak): bucket = 4 - 3 = 1
    ✅ Output → Bucket state: 4


Packet 2: size = 2

  • Check: 2 + 1 <= 10 → OK

  • Add: bucket = 1 + 2 = 3

  • Leak: bucket = 3 - 3 = 0
    ✅ Output → Bucket state: 3


Packet 3: size = 6

  • Check: 6 + 0 <= 10 → OK

  • Add: bucket = 0 + 6 = 6

  • Leak: bucket = 6 - 3 = 3
    ✅ Output → Bucket state: 6


Packet 4: size = 3

  • Check: 3 + 3 <= 10 → OK

  • Add: bucket = 3 + 3 = 6

  • Leak: bucket = 6 - 3 = 3
    ✅ Output → Bucket state: 6


Packet 5: size = 5

  • Check: 5 + 3 <= 10 → OK

  • Add: bucket = 3 + 5 = 8

  • Leak: bucket = 8 - 3 = 5
    ✅ Output → Bucket state: 8


3️⃣ What happens if capacity is exceeded?

If size + bucket > bucket_capacity,
→ The packet is dropped and a message is printed.

Example: If bucket is 9 and a packet of size 4 arrives,
9 + 4 = 13 > 10 → Packet dropped.


4️⃣ Why it’s called “Leaky Bucket”

  • Imagine water filling a bucket at different rates (packet arrival)

  • Water leaks out at a fixed rate (output_rate)

  • If too much water comes in at once, it overflows (packet drop)

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Bucket state: 4
Bucket state: 3
Bucket state: 6
Bucket state: 6
Bucket state: 8

 

Program 9: Frame Sorting in Buffer

Aim:
To sort frames received out of order.

def frame_sorting(frames):
    sorted_frames = sorted(frames)
    print("Sorted Frames:", sorted_frames)

frame_sorting([5, 2, 1, 4, 3])

1️⃣ Purpose

This simulates sorting of frames in networking.
In real networks, frames (data packets) might arrive out of order, and before processing, they need to be reordered.

2️⃣ Code Walkthrough

 

python

CopyEdit

def frame_sorting(frames): sorted_frames = sorted(frames) print("Sorted Frames:", sorted_frames)

  • frames → List of frame numbers

  • sorted(frames) → Uses Python’s built-in sorting (ascending order by default)

  • Prints the sorted order


3️⃣ Execution

Input:

 

python

CopyEdit

frame_sorting([5, 2, 1, 4, 3])

Step-by-step sorting:

  • Start: [5, 2, 1, 4, 3]

  • Compare & rearrange → [1, 2, 3, 4, 5]

Output:

 

less

CopyEdit

Sorted Frames: [1, 2, 3, 4, 5]


4️⃣ Networking Analogy

Imagine you’re receiving video frames:

 

mathematica

CopyEdit

Frame 5 → Frame 2 → Frame 1 → Frame 4 → Frame 3

If you display them immediately, the video will look jumbled.
Sorting ensures:

 

mathematica

CopyEdit

Frame 1 → Frame 2 → Frame 3 → Frame 4 → Frame 5

✅ Smooth playback.

================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Sorted Frames: [1, 2, 3, 4, 5]

 

Program 10: Wireshark Usage

Aim:
To learn basic Wireshark functionalities:

  • i. Packet Capture using Wireshark

  • ii. Starting Wireshark

  • iii. Viewing Captured Traffic

  • iv. Using Analysis and Statistics, Filters

💡 Use filters like ip.addr == 192.168.1.1, tcp.port == 80, etc.

 

Program 11: Nmap Scan

Aim:
To run a basic Nmap scan on a network.

 

nmap 192.168.1.1
nmap -sP 192.168.1.0/24

 

 

Program 12: OS Detection with Nmap

Aim:
To detect Operating Systems of target hosts using Nmap.

nmap -O 192.168.1.1

 

Program 13: NS2 Simulator Introduction

Aim:
To understand how to simulate networks using NS2.

  • Install NS2

  • Run .tcl script

  • Observe using nam 

# Sample NS2 script
set ns [new Simulator]
set n0 [$ns node]
set n1 [$ns node]
$ns duplex-link $n0 $n1 1Mb 10ms DropTail