Bamdeb Ghosh – Linux Hint https://linuxhint.com Exploring and Master Linux Ecosystem Mon, 08 Feb 2021 18:31:04 +0000 en-US hourly 1 https://wordpress.org/?v=5.6.2 Macro in C language https://linuxhint.com/write-macro-c-language/ Sun, 07 Feb 2021 13:00:01 +0000 https://linuxhint.com/?p=89164 A macro in C language is a piece of code which has been assigned a name. When the name is used anywhere in the program, the macro value is replaced before the program’s compilation. In this article, we will see in detail how to write a macro in C language.

Consider the following code:

START

    INTEGER n=5;
   
    PRINT("Value of n is %d",n);

END

The above code is not a valid C code.

But the following code is valid:

//Example1.c
#define START int main(){
#define END }
#define INTEGER int
#define PRINT(A,B) printf(A,B)


START

    INTEGER n=5;
   
    PRINT("Value of n is %d",n);

END

Before compilation, the macro START, INTEGER, PRINT and END has been replaced by their value, and the code becomes a valid C code. We can check using the following command:

gcc –E Example1.c

This command will show after expanding all the macros.

Now we will see different types of macros:

1. Object-like macros:

Syntax:

#define macro_name  macro_value
  • Macro is always starting with #define
  • macro_name is a user-defined name of the macro
  • macro_value is the value of the macro. It may be anything, but one line and the macro body ends with that line’s ends. It does not require semicolon (;) at the end. Space is also considered.

If the macro takes more than one line we can do it as follows:

#define macro_name  macro_value1 \
                    macro_value2 \
                    macro_value3


#define MAX 200

This macro looks like a data object that’s why this type of macro called as an object-like macro.

//Example2.c  
//#include <stdio.h>
#define MAX 200  
     
int main()  
{  
    printf("MAX Value is: %d",MAX);  
    return 0;
}

In Exapmle2.c, MAX is a macro. From the output, we observe that MAX is replaced by its value 200.

2. Function-like macros:

Syntax:

#define macro_name()  macro_value

macro_name is a user-defined name of the macro. Pair of parenthesis has to put after the macro_name. No space is allowed between macro_name and parenthesis. We also can pass arguments in this type of macros.

#define add(x,y) x+y

This macro looks like a function call that’s why this type of macro called a function-like macro.

//Example3.c  
     
#define add(x,y) x+y  
     
int main()  
{  
     
    int a;  
    float b;  
     
    a = add(4,5);  
    b = add(2.5,3.6)  
         
    return 0;
}

In Example3.c, we have seen that unlike C’s function, the macro replace only the code with arguments without calculating it. So, we can pass different data type using the same macro.

If we put a space between the macro name and parenthesis, it works the same as an object-like macro. Below C Example illustrates this.

//Example4.c  
 
#define add (x,y) x+y  
 
int main()  
{  
 
    int a;  
    float b;  
     
    a = add(4,5);  
    b = add(2.5,3.6)
}

In Example4.c, we have seen that the macro add is replaced by (x,y) x+y . Same as an object-like macro.

3. Macro for Token Pasting:
In C language, ## operator is used for token pasting. Using this operator, we can combine two valid tokens into one valid token.
Example:

//Example5.c  
#define MARGE(x,y) x##y  
 
int main()  
{  
 
    int num = MARGE(52,34);  
    return 0;
}

If we try to token pasting that does not generate a valid token, the C compiler gives an error or warning.

//Example6.c  
#define MARGE(x,y) x##y  
 
int main()  
{  
 
    int num = MARGE(52,+);  
    return 0;
}

In Example6.c, we have an error message because, after a combination of two tokens, we get an invalid token ’52+’.

4. Macro for Stringizing:
In C language, # operator is used to converting a macro parameter into a string constant. When a # operator precedes with a macro parameter, the parameter converts to a string literal. Stringizing can be used for object-like and function-like macros.
Example:

//Example7.c  
#define STRINGIZING(x) #x  
 
int main()  
{  
 
    printf(STRINGIZING(Hello World) );  
    return 0;
}

In Example7.c we have got a string “Hello World” using STRINGIZING macro.

Conclusion:

This article has learned about all types of macro-like Object-like macros, Function-like macros, Macro for Token Pasting, Macro for Stringizing and Macro for Stringizing in C language. Now we can use a macro in our C program without any doubt. ]]> Python Lambda https://linuxhint.com/python-lambda/ Sat, 30 Jan 2021 16:51:13 +0000 https://linuxhint.com/?p=88062

In this article, we will try to learn about Python Lambda.

Definition

Lambda is a function defined without a name. This can take multiple arguments, but only one expression is allowed that is evaluated and returned. Where function objects are required, we can use the lambda function.

Syntax:
lambda arguments: expression

Example 1: The function below is used to calculate the cube of a number.

def cube(a):  
    return a*a*a  
print(cube(3))

The above function can be written using lambda, as shown below:

p = lambda x : x*x*x  
print(p(3))

Example 2: The function below is used to calculate the sum of two numbers.

def sum_2(x,y):  
    return x + y  
print(sum_2(10,20))

The above function can be written using lambda, as shown below:

p = lambda x,y : x + y  
print(p(10,20))

Example 3: The example below for lambda takes multiple arguments.

p = lambda x, y, z : x + y + z  
print(p(10, 5, 3))

Example 4: This function multiplies the number by 2 and can be written using Lambda function as below:

def func(n):  
  return lambda x : x * n  

multiply_by_2 = func(2)  
print(multiply_by_2(11))  
print(multiply_by_2(15))

Example 5: The function takes function as an argument and returns the result.

function_argument = lambda p, f: p + f(p)  
print(function_argument(5, lambda p: p * p))  
print(function_argument(10, lambda x: x - 3))  
print(function_argument(10, lambda x: x + 5))  
print(function_argument(10, lambda x: x / 5))

Example 6: In the example below, lambda is used to sort the values.

#(name,surname,age)  
data = [("Sachin", "Tendulkar", "42"), ("Rahul", "Dravid", "44"), ("Virendra", "Sehwag", "40")]  
data.sort(key=lambda x:x[0])#sort based on name  
print(data)  
data = [("Sachin", "Tendulkar", "42"), ("Rahul", "Dravid", "44"), ("Virendra", "Sehwag", "40")]  
data.sort(key=lambda x:x[1])#sort based on surname  
print(data)  
data = [("Sachin", "Tendulkar", "42"), ("Rahul", "Dravid", "44"), ("Virendra", "Sehwag", "40")]  
data.sort(key=lambda x:x[2])#sort based on age  
print(data)

Now, go into python3 interpreter.

The lambda function is used in many inbuilt methods. The following are some examples:

1. Map

This function maps each element in sequence using the lambda function.

Syntax:
map(function, seq)

Ex:
nums = [1,2,3,4,5,6]
Here, we will multiply each element in the list by 2.
mul_2 = map(lambda x: x*2, nums)
print(list(mul_2)) # It returns map object and typecasting it as list.

In the above function, each element of thelist is passed to the lambda function and the lambda function will multiply it by 2.

nums = [1,2,3,4,5,6]  
mul_2 = map(lambda x: x*2, nums)  
print(list(mul_2))

2. Filter

This function filter out all the elements of a list for which the lambda function returns True.

Syntax:
filter(function, seq)

Ex:
nums = [0,1,2,3,4,5,6,7,8,9,10]
odd_nums = filter(lambda x: x % 2, nums)
print(list(odd_nums)) # It returns map object, and typecasting it as list.

nums = [0,1,2,3,4,5,6,7,8,9,10]  
odd_nums = filter(lambda x: x % 2, nums)  
print(list(odd_nums))

3. Reduce

This function returns a single value by applying function func() to the seq.

Syntax:
reduce(func, seq)

Ex:
nums = [0,1,2,3,4,5,6,7,8,9,10]
value = reduce(lambda x,y: x+y, nums)
print(value)

In the above list, it will take the first 2 elements and perform addition. The result of an addition will be added to the third element and so on. Finally, it will return a single value.

Note: This method is not available in the python3+ version.

nums = [0,1,2,3,4,5,6,7,8,9,10]  
value = reduce(lambda x,y: x+y, nums)  
print(value)

Conclusion

From this article, we have learned many aspects of the lambda function. Depending on what the program needs, we can use it and make better python coding. This is most commonly used to pass arguments to another function (for example, we have seen above functions map, filter, and reduce).

]]>
Python File Handling https://linuxhint.com/python-file-handling/ Fri, 15 Jan 2021 20:49:36 +0000 https://linuxhint.com/?p=85848 In this article, we are going to discuss Python File handling.

Definition
In Python, a file is a location on disk used to store information, which some names are associated with it. It is used to store data permanently in a non-volatile (non-volatile means retains data even if power loss) memory (Ex: hard disk).

Syntax
file_pointer = open(filelocation, modes, encoding= encoding_type)
encoding is an optional parameter

Files can be opened in any of the following modes:

  • r –> read mode
  • w –> write mode
  • a –> append mode
  • +  ->  append this to the above modes to open the file for reading and write modes Ex: r+

To open a file in binary mode append “b“ to the above modes.

Ex: To open the file a binary file in readmode use “rb“.

How to enter into python interpreter?

Open Linux terminal and type “python” and hit enter so we will see python interpreter. For python3+ version type “python3”,  we are going to see the following info on the terminal. If we want to check the Python version, type “python -v”.

In Python a file, this  operation is performed in the following order:

  1. Open a file
  2. Read or write or append: When we specify write mode, the file will be opened in write mode if it exists, otherwise, it is going to create the file. This is applicable for append mode also. In read mode, if file exists, it opens in the read mode, otherwise, throws FileNotFoundError exception.
  3. Close the file

Open a file

Inbuilt method open() used.

Ex:

f = open("firstfile.txt")   # In python, default is read mode.
f = open("textfile.txt",'w')  # write in text mode
f = open("abc.bmp",'r+b') # read and write in binary mode

Closing a file

Inbuilt method close() used.

Ex:

fp = open("textfile.txt",encoding = 'utf-8')
# perform some file operations
fp.close()


Safer way to open and close files using exception handling:

try:    
    fp = open("textfile.txt",'r',encoding = 'utf-8')    
    # perform some file operations  
finally:    
    fp.close()

Using this method, we are making sure that the file is closed always.

File operations using with

The best way to perform file operation and most commonly used method with statement. Using this ensures that the file is closed when the block inside with is exited.

Ex:

open(‘textfile.txt, ‘w’, encoding = 'utf-8') as fp:
#perform some file operations
#statements outside the with block

When we exit with block, the file will be closed automatically.

Write to File

To write into a file, we need to open it in write ‘w’ or append ‘a’.

To write to a file, python has the following inbuilt methods:

write(): This method writes the string to a file.

Ex:

with open("textfile.txt",'w',encoding = 'utf-8') as f:    
    f.write("This is a first line\n")    
    f.write("Good morning\n")    
    f.write("This is a example for file write operation\n")    
    f.write("file contains four lines")

If we open the textfile.txt file, we see the above lines are written successfully.

writelines() : This method writes the list of strings to a file.

Ex:

file_content = ["This is a first line\n","Good morning\n",  
                "This is a example for file write operation\n",  
                "file contains four lines"]    
with open("textfile.txt",'w',encoding = 'utf-8') as f:    
    f.writelines(file_content)

Reading from file

To read a file in Python, we must open the file in reading mode ‘r’.

To read from a file, python has the following inbuilt methods:

read():   

read(4): This method reads the first 4 characters from the file.

Ex:

fp = open("textfile.txt",'r',encoding = 'utf8')#provide location of textfile.txt file
print(fp.read(4))#It will read first 4 characters    
fp.close()

read() : This method reads till end of file.

Ex:

fp = open("textfile.txt",'r',encoding = 'utf8')#provide location of textfile.txt file
print(fp.read())#It will read till EOF  
fp.close()

readline(): This method reads one line at a time.

Ex:

fp = open("textfile.txt",'r',encoding = 'utf8')#provide location of textfile.txt file
print(fp.readline(), end="")#It will read first line    
print(fp.readline(), end="")#It will read second line    
fp.close()

readlines(): This method read all lines in the file and returns a list.

Ex:

fp = open("textfile.txt",'r',encoding = 'utf8')#provide location of textfile.txt file
print(fp.readlines())# read all ines in the file    
fp.close()

for loop: This is the most commonly used way of reading a file. We can read a file line by line using a forloop. This is an efficient and fast way of reading a file.

Ex:

fp = open("textfile.txt",'r',encoding = 'utf-8')#provide location of textfile.txt file
for line in fp:    
    print(line, end='')    
fp.close()

Traverse in a file

The following methods are used to traverse in a file.

tell(): This method is used to get the current file position in a file.

Ex:

with open("textfile.txt", "r") as fp:#provide location of textfile.txt file  
    fp.read(6)  
    print(fp.tell())  
    fp.close()

seek(): This method used to bring/place file cursor to a given position in a file.

Ex:

with open("textfile.txt", "r") as fp:#provide location of textfile.txt file  
    fp.seek(7)    
    print(fp.readline())

truncate(): This method is used to modify/resize the file to a specified size in a file.

Ex:

#writing to a file  
with open("textfile.txt",'w',encoding = 'utf-8') as f:    
    f.write("This is a first line\n")    
    f.write("Good morning\n")    
    f.write("This is a example for file write operation\n")    
    f.write("file contains four lines")  
#Apply truncate method  
fp = open("textfile.txt", "a")#provide location of textfile.txt file    
fp.truncate(25)    
fp.close()    
#reading the file after the truncate  
fp = open("textfile.txt", "r")    
print(fp.read())

flush() : This method flush/clear a buffer.

Ex:

fp = open("textfile.txt", "w")#provide location of textfile.txt file    
fp.write("good morning!\n")    
fp.flush()    
fp.write("good evening!")  
fp.close()

Conclusion

In Python, a file is a location on a disk that is used to store information. File handling in Python is simple and easy. Also, in Python, different modules are available for handling different typess of files.

Ex:

File type Python module
csv csv
xml xml
excel xlrd
]]>
Decrypting SSL/TLS Traffic with Wireshark https://linuxhint.com/decrypt-ssl-tls-wireshark/ Sat, 26 Dec 2020 11:06:09 +0000 https://linuxhint.com/?p=82990

In this article, we will make Linux set up and capture HTTPS (Hypertext Transfer Protocol Secure) packets in Wireshark. Then we will try to decode the SSL (Secure Socket Layer) encryptions.

Note that: Decryption of SSL /TLS may not work properly through Wireshark. This is just a trial to see what is possible and what is not possible.

What are SSL, HTTPS, and TLS?

Actually, all these three technical terms are interrelated. When we use only HTTP (Hypertext Transfer Protocol), then no transport layer security is used and we can easily see the content of any packet. But when HTTPS is used then we can see TLS (Transport Layer Security) is used to encrypt the data.

Simply we can say.

HTTP + (over) TLS/SSL = HTTPS

Note: HTTP sends data over port 80 but HTTPS uses port 443.

Screenshot for HTTP Data:

Screenshot for HTTPS Data:

Make Linux set up for SSL packet description

Step 1
Add below environment variable inside the .bashrc file. Open the .bashrc file and add the below line at end of the file. Save and close the file.

export SSLKEYLOGFILE=~/.ssl-key.log

Now execute the below command to get the effect of it.

source ~/.bashrc

Now try the below command to get the value of “SSLKEYLOGFILE”

echo $SSLKEYLOGFILE

Here is the screenshot for all the above steps

Step 2
The above log file is not present in Linux. Create the above log file in Linux. Use the below command to create a log file.

touch ~/.ssl-key.log

Step 3
Launch default installed Firefox and open any https site like Linuxhint or Upwork.

Here I have taken the first example as upwork.com.

After the upwork website is opened in Firefox, check the content of that log file.

Command:

cat ~/.ssl-key.log

If this file is empty then Firefox is not using this log file. Close Firefox.

Follow the below commands to install Firefox.

Commands:

sudo add-apt-repository ppa:ubuntu-mozilla-daily/firefox-aurora
sudo apt-get update
sudo apt-get install firefox

Now, launch Firefox and check the content of that logfile

Command:

cat ~/.ssl-key.log

Now we can see huge information like the below screenshot. We are good to go.

Step 4
Now we need to add this log file inside Wireshark. Follow below path:

Wireshark->Edit->Preferences->Protocol->SSL->”Here provide your master secret log file path”.

Follow the below screenshots for visual understanding.

After doing all these settings, do OK and start Wireshark on the required interfaces.

Now the set up is ready to verify SSL decryption.

Wireshark Analysis

After Wireshark starts capturing, put filter as “ssl” so that only SSL packets are filtered in Wireshark.

Look at the below screenshot, here we can see HTTP2 (HTTPS) is opened for some packets which were SSL/TLS encryption before.

Now we can see the “Decrypted SSL” tab in Wireshark and HTTP2 protocols are opened visible. See the below screenshot for pointers.

Let’s see the differences between “Before SSL log file enabled” and “After SSL log file enabled” for https://linuxhint.com

Here is the screenshot for packets of Linuxhint when “SSL log was not enabled”

Here is the screenshot for packets of Linuxhint when “SSL log was enabled”

We can see the differences easily. In the second screenshot, we can clearly see the URL that was requested by the user.

https://linuxhint.com/bash_scripting_tutorial_beginners/\r\n

Now we can try other websites and observe if these methods work or not.

Conclusion

The above steps show how to make Linux set up to decrypt SSL/TLS encryption. We can see it worked well but some packets are still SSL/TLS encrypted. As I mentioned earlier it may not work for all packets or completely. Still, it’s good learning about SSL/TLS decryption.

]]>
Python Decorators https://linuxhint.com/python-decorators/ Thu, 03 Dec 2020 04:12:28 +0000 https://linuxhint.com/?p=78759 In this article, we are going to discuss Python Decorators.

Definition: Decorator is a design pattern in Python. It is a function that takes another function as an argument, add some functionality to it without modifying it, and returns another function.

This is called using “(@)” and placed before defining a function that we want to decorate.

syntax:

@decorator name
Function definition

For understanding decorators, we need to know the below concepts.
Functions are first-class objects. It means a function can be passed as an argument, can be returned from another function, can be assigned to a variable, can be defined in another function. For a better understanding, see the below examples.

  1. A function can be passed as an argument
    Ex:

    def increment(n):
      return n + 1

    def demo_funcall (function):
      num = 5
      return function(num)

    demo_funcall (increment)

    Here increment function passed as an argument

    example1.py:

    Output:

    >> python example1.py

  2. Function can be returned from another function
    Ex:

    def wish():
        def say_wish():
          return "Happy Birthday"
        return say_wish

    hello = wish()
    hello()

    example2.py:

    Output:

    >>python example2.py

    Here say_wish function returned from the wish function

  3. Function can be modified and assigned to a variable
    Ex:

    def add(a,b):
           return a +b

    sum2nos = add # Here function add assigned to variable
    sum2nos(5,11)

    example3.py:

    Output:
    >> python example3.py

  4. Define function inside another function
    Ex:

    def add(a,b):
            def sum2(a,b):
                return a + b
            res = sum2(a,b)
            return res
    add(10,15)

    example4.py:

    Output:
    >> python example4.py

Closure:

Python allows a nested function to access the outer scope of the enclosing function.

def greeting(message):
    "Enclosong Function"
    def send_greeting():
        "Nested Function"
        print(message)
    send_greeting()

greeting("Good morning")

example5.py:

Output:

>> python example5.py

After understanding the above concepts now, we will write a decorator example.

Ex1: Here, we will decorate the message function. Printing the msg inside **** without modifying the original function, i.e., message function.

#decorator start
def print_msg(function):
    def wrapper():
        function()
    return wrapper
#decorator end

def message():
    print(“This is first example for demonstrating decorator”)

hello = print_msg(message)
hello()

example6.py:

Output:

>> python example6.py

In the simplest form, we can place decorator on top of the function definition and call the function as shown below:

Here whatever string we want to decorate inside ***, use this decorator.

Output:

Multiple decorator:

We can have multiple decorator for a single function. Here the decorator is applied in the order we called.
syntax:
@decorator2
@decorator1
Function definition

Here 1st decorator will be applied, then 2nd decorator.

Passing arguments to decorator functions:

We can pass arguments to the wrapper function. The arguments passed to the function for which we want to decorate.

Ex:

def deco_wish(function):
    def wrapper (arg1, arg2):
        print (‘The passed arguments are ’,arg1, arg2)
        print (‘*********************’)
        function (arg1, arg2)
        print (‘*********************’)
    return wrapper

@deco_wish
def wish(a1, a2):
    print(a1,a2)
wish (‘Good’, ’Morning’)
wish (‘Good’, ’Afternoon’)

example7.py:

Output:

>> python example7.py

Pass variable number of arguments to decorator function:

We can pass any number of arguments using *args (Non-keyword arguments like numbers) and **kwargs (keyword arguments like a dictionary). Both are positional arguments and stores the arguments in args and kwargs variables.

Note: Here, we can use any name instead of args and kwargs, but these names are recommended to use.

Ex:

def dec_var_args(funtion):
    def wrapper(*args, **kwargs):
        print(‘The non keyword arguments are’, args)
        print(‘The keyword arguments are’, kwargs)
        function(*args)
    return wrapper

@ dec_var_args
def fun_non_key_args(*args):
    for I in args:
        print(i)

@ dec_var_args
def fun_key_args():
    print(“Keyword arguments”)

fun_non_key_args((4,5,6))
fun_key_args(fname=’Anand’, lname=’Math’)

example8.py:

Output:

>> python example8.py

Ex2: Suppose we have 2 function
Function1: Calculate the sum of numbers from the given list
Function2: Multiply each number by 2 and add them to the given list of numbers
If we want to calculate the time taken by each for execution, can do it in 2 ways

  1. Place code in between the start and end time in each function
  2. Write decorator for calculating time

See below code solved using decorator:

#decorator start
exe_time_calc(func):
    def wrapper(arg):
        start_time = datetime.datetime.now()
        func(arg)
        end_time = datetime.datetime.now()
        print ("The time take for executing function " + func.__name__  + " is " + str(end_time - end_time))
    return wrapper
#decorator end

@exe_time_calc
def cal_avg(data):
    sum = 0
    for i in data:
        sum += i
    print ("The average of given list of numbers is ", sum//len(data))

@exe_time_calc
def mul_by_2(data):
    sum = 0
    for i in data:
        sum += + (i*2)
    print ("The sume of all numbers after multiply by 2 is ", sum)

cal_avg ([10,20,30,40,50])
mul_by_2([10,20,30,40,50])

example9.py:

Output:

>> python example9.py

The above decorator can be used for calculating execution time for any of the functions. By using a decorator, we can avoid repeated code when we have a requirement for calculating the execution time to place the decorator above the function definition.

Conclusion:

Decorators change the functionality of a function/method without changing the original code of the function is being decorated. Using this, we can avoid writing repeated code. Knowing the decorator concept will make us strong in python. We can use decorator in the below cases:

  • Authorization in Python frameworks Ex: Flask and Django
  • Logging
  • Measure execution time
]]>
2D Array https://linuxhint.com/2d-array-in-c-program/ Thu, 26 Nov 2020 14:37:15 +0000 https://linuxhint.com/?p=78234 A Two-dimensional (2D) array is an array of one dimensional (1D) arrays. The 1D array sizes are equal. The 2D array is also called a matrix with rows and columns.

Let’s see the following example:

These 3 1D arrays can be represented as a 2D array as follows:

Let’s see another example:

These 3 1D arrays cannot be representing as a 2D array because the sizes of the arrays are different.

Declaration of 2D array

data-type array-name[ROW][COL]

  • Data-type is the data type of the array elements.
  • Array-name is the name of the array.
  • Two subscripts represent the number of rows and columns of the array. The total number of elements of the array will be ROW*COL.

int a[2][3];

Using the above C code, we can declare an integer array, a of size 2*3 (2 Rows and 3 Columns).

char b[3][2];

Using the above C code, we can declare a character array, b of size 2*3 (3 Rows and 2 Columns).

Initialization of 2D array

We can initialize during declaration in following ways:

  1. int a[3][2] = {1,2,3,4,5,6};
  2. int a[][2] = {1,2,3,4,5,6};
  3. int a[3][2] = {{1, 2},{3, 4},{5, 6}};
  4. int a[][2] = {{1, 2},{3, 4},{5, 6}};

Note that in 2 and 4 we have not mentioned the 1st subscript. The C compiler automatically calculates number of rows from the number of elements. But the 2nd subscript must be specified. Following initializations are invalid:

  1. int a[3][] = {1,2,3,4,5,6};
  2. int a[][] = {1,2,3,4,5,6};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Example1.c  
#include  
#define ROW 3  
#define COL 2  
 
int main()  
{  
    int i,j;  
    int a[ROW][COL] = {  
        {1,2},  
        {3,4},  
        {5,6}  
    };  
     
    printf("Row wise Elements of the array a are :\n");  
     
    for(i=0;i<ROW;i++)  
    {  
        printf("Row %d:",i);  
        for(j=0;j<COL;j++)  
        {  
            printf(" %d",a[i][j]);  
        }  
        printf("\n");  
    }    
     
    printf("\n\nColumn wise Elements of the array a are :\n");  
     
    for(i=0;i<COL;i++)  
    {  
        printf("Column %d:",i);  
        for(j=0;j<ROW;j++)  
        {  
            printf(" %d",a[j][i]);  
        }  
        printf("\n");  
    }  
     
    return 0;  
}

In Example1.c, we have declared an integer array of size 3*2 and initialized. To access array elements, we use two for loop.

To access row-wise, the outer loop is for rows, and the inner loop is for columns.

To access column-wise, the outer loop is for columns, and the inner loop is for rows.

Note that when we declare a 2D array, we use a[2][3], which means 2 rows and 3 columns. Array indexing starts from 0. To access the 2nd row and 3rd column, we have to use the notation a[1][2].

Memory mapping of a 2D array

The logical view of an array a[3][2] may be as follows:

Computer memory is a 1D sequence of bytes. In C language, a 2D array store in the memory in row-major order. Some other programming languages (e.g., FORTRAN), it stores in column-major order in the memory.

Pointer Arithmetic of a 2D array

To understand the pointer arithmetic of the 2D array, first, have a look at the 1D array.

Consider a 1D array:

In 1D array, a is a constant, and its value is the address of the 0th location of the array a[5]. Value of a+1 is the address of the 1st location of the array a[5].  a+i is the address of the ith location of the array.

If we increment a by 1, it is incremented by the size of the data type.

a[1] is equivalent to *(a+1)

a[2] is equivalent to *(a+2)

a[i] is equivalent to *(a+i)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Example2.c  
#include  
#define ROW 3  
#define COL 2  
 
int main()  
{  
    int a[5]={10,20,30,40,50};  
 
    printf("sizeof(int): %ld\n\n",sizeof(int));  
 
    printf("a: %p\n",a);  
    printf("a+1: %p\n",a+1);  
    printf("a+2: %p\n\n",a+2);  
 
    printf("a[1]: %d,  *(a+1): %d\n",a[1],*(a+1));  
    printf("a[2]: %d,  *(a+2): %d\n",a[1],*(a+1));  
    printf("a[3]: %d,  *(a+3): %d\n",a[1],*(a+1));  
     
    return 0;  
}

In Example2.c, the memory address is showing in hexadecimal. The difference between a and a+1 is 4, which is the size of an integer in bytes.

Now, consider a 2D array:

b is a pointer of type: int[ ][4] or int(*)[4]

int[ ][4] is a row of 4 integer. If we increment b by 1, it is incremented by the size of the row.

b is the address of the 0th row.

b+1 is the address of the 1st row.

b+i is the address of ith row.

The size of a row is: ( Number of column * sizeof(data-type)) bytes

Size of a row of an integer array b[3][4] is: 4 * sizeof(int) = 4 * 4 = 16 bytes

A row of a 2D array may be viewed as a 1D array. b is the address of the 0th row. So, we get the following

  • *b+1 is the address of the 1st element of the 0th
  • *b+j is the address of the jth element of the 0th
  • *(b+i) is the address of the 0th element of the ith
  • *(b+i)+j is the address of the jth element of the ith
  • b[0][0] is equivalent to **b
  • b[0][1] is equivalent to *(*b+1)
  • b[1][0] is equivalent to *(*(b+1))
  • b[1][1] is equivalent to *(*(b+1)+1)
  • b[i][j] is equivalent to *(*(b+i)+j)

Address of b[i][j]: b + sizeof(data-type) * ( Number of column * i + j)

Consider a 2D array: int b[3][4]

Address of b[2][1] is : b + sizeof(int) * (4*2 + 1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Example3.c  
#include  
#define ROW 3  
#define COL 4  
 
int main()  
{  
    int i,j;  
    int b[ROW][COL] = {  
        {10,20,30,40},  
        {50,60,70,80},  
        {90,100,110,120}  
    };  
     
    printf("sizeof(int): %ld\n",sizeof(int));  
    printf("Size of a row: %ld\n",COL*sizeof(int));  
    printf("b: %p\n",b);  
    printf("b+1: %p\n",b+1);  
    printf("b+2: %p\n",b+2);  
    printf("*b: %p\n",*b);  
    printf("*b+1: %p\n",*b+1);  
    printf("*b+2: %p\n",*b+2);  
    printf("b[0][0]: %d    **b: %d\n",b[0][0],**b);  
    printf("b[0][1]: %d    *(*b+1): %d\n",b[0][1],*(*b+1));  
    printf("b[0][2]: %d    *(*b+2): %d\n",b[0][2],*(*b+2));  
    printf("b[1][0]: %d    *(*(b+1)): %d\n",b[1][0],*(*(b+1)));  
    printf("b[1][1]: %d    *(*(b+1)+1): %d\n",b[1][1],*(*(b+1)+1));  
     
    return 0;  
}

In Example3.c, we have seen that size of a row is 16 in decimal notation. The difference between b+1 and b is 10 in hexadecimal. 10 in hexadecimal is equivalent to 16 in decimal.

Conclusion

So, in this article, we have learned about

  1. Declaration of 2D array
  2. Initialization of 2D array
  3. Memory mapping of 2D array
  4. Pointer Arithmetic of 2D array

Now we can use 2D array in our C program without any doubt,

References

Credit for some ideas in this work were inspired by the course, Pointers and 2-D Arrays, by Palash Dey Department of Computer Science & Engg. Indian Institute of Technology Kharagpur

]]>
Why does Wireshark say no interfaces found https://linuxhint.com/wireshark-detecting-no-interfaces/ Sun, 22 Nov 2020 12:04:40 +0000 https://linuxhint.com/?p=77794 Wireshark is a very famous, open-source network capturing and analyzing tool. While using Wireshark, we may face many common issues. One of the common issues is “No Interfaces are listed in Wireshark”. Let’s understand the issue and find a solution in Linux OS.If you do not know Wireshark basic, then check Wireshark Basic first, then come back here.

No Interfaces are listed in Wireshark:

Let’s see this issue and try to solve it.

Step1:

First of all, we need to see how many interfaces are there in our Linux PC.

We can use the command “ifconfig” to see a list of up interfaces in our Linux pc. So open terminal (Short cut Alt+Ctrl+t) and run command “ifconfig

Outputs:

It should list down all up interfaces. Here is the screenshot for the “ifconfig” output

E:\fiverr\Work\Linuxhint_mail74838\Article_Task\c_c++_wireshark_15\bam\pic\inter_1.png

Here we can see three interfaces, including loopback interface “lo”.

If we want to see all interfaces in our system, including down interfaces, then use the command “ifconfig -a

Step2:

Now launch Wireshark from the command line.

“wireshark”

Screenshot:

Output:

E:\fiverr\Work\Linuxhint_mail74838\Article_Task\c_c++_wireshark_15\bam\pic\inter_2.png

Now we do not see the interfaces that we have seen from the previous output of the “ifconfig” command. On the right side, we can see “All interfaces shown” is selected.

Then what is the issue? Why Wireshark not able to detect required interfaces?

Let’s see.

Step3:

Close Wireshark and come back to the terminal. Here we can see the user is a normal user [Example: “rian”], but we need to launch Wireshark in superuser mode; otherwise, Wireshark is allowed to access the system interface list. Let’s try it out.

su” and enter the root password.

Output:

Now we can see the prompt as “root@”. This means we are in root. Let’s try to launch Wireshark again from the terminal.

“wireshark”

Output:

E:\fiverr\Work\Linuxhint_mail74838\Article_Task\c_c++_wireshark_15\bam\pic\inter_3.png

All interfaces are listed down here on the Wireshark home page. Required interfaces are marked with a blue circle. These are the same interfaces that we have seen in the “ifconfig” command output.

In Linux, running Wireshark in sudo or superuser mode solves the problem.

We have seen in superuse mode. Let’s try if doing “sudo” works or not.

Command sequences:

1. Close Wireshark and enter “exit” to come out from the root.

2. Type the command “sudo wireshark” and enter the password for user “rian”. No need of a root password.

Here is the screenshot for the above steps 1 and 2.

Here is the home screen of Wireshark

All interfaces are listed down here.

Capturing Test:

Note: “enp1s0” is an Ethernet interface, and “wlp2s0” is a Wi-Fi interface.

As we see, interfaces are listed down, so let’s try to capture in one interface to see if it’s working or not.

See the below screenshot and double-click on the first interface.

E:\fiverr\Work\Linuxhint_mail74838\Article_Task\c_c++_wireshark_15\bam\pic\inter_4.png

As soon as we double click on the “enp1s0” interface, it starts capturing. Here is the screenshot for live capturing on interface “enp1s0”

E:\fiverr\Work\Linuxhint_mail74838\Article_Task\c_c++_wireshark_15\bam\pic\inter_5.png

We can try on capturing other interfaces also to see if it’s working.

Now double click on “wlp2s0” to start capturing. Here is the screenshot for live capturing.

E:\fiverr\Work\Linuxhint_mail74838\Article_Task\c_c++_wireshark_15\bam\pic\inter_6.png

Conclusion

In this article, we have learned how to solve the problem when Wireshark cannot detect or list down all interfaces from the Linux system. And there are two ways we can resolve this; either launch Wireshark in superuser mode or using sudo.

]]>
How to work with Python Tuples? https://linuxhint.com/how-to-work-with-python-tuples/ Sun, 15 Nov 2020 10:25:16 +0000 https://linuxhint.com/?p=76848 In this article, we are going to discuss tuples, an ordered and immutable data type (read only). It can have similar or different data type elements, and is declared in parenthesis ().

Syntax:

t = (1,2,0.5,’jki’,’hi’,6)

We need to take special care when we declare tuple with single element.

t = (2,)

If we omit comma (,) here, it will be a normal integer variable.

In the first example, the type is tuple.

In the second example, the type is integer.

Other way of declaring a tuple:

t = 1,2,3,4,’hi’

How to enter into Python interpreter?

Open Linux terminal and type “python”, then hit enter so we will see python interpreter. For python3+ version, type “python3”, these are the following info we are going to see on the terminal. If we want to check python version, type “python -v”.

Output:

Python 3.5.0 (default, Sep 20 2019, 11:28:25)
[GCC 5.2.0] on Linux
Type "help", "copyright", "credits", or "license" for more information.
>>>

The following operations can be performed on tuple:

Tuple Slice

This is useful when we want only part of the tuple.

Note: Tuple index always starts from 0. Tuple can be traversed in forward and reverse direction (using negative index).

Example:

t = (1,2,3,4,’hi’,’good’,10.5)
Forward traverse index: [0,1,2,3]
reverse traverse index: [,-3,-2,-1] here t[-1]=10.5, t[-2]=”good”,
 t[-3]=”hi”, t[-4]=4,

Syntax:

variablename[start:stop:step].

Here, stop is excluded. If we provide only start, it will extract all the elements from start to end of tuple. If we provide only stop, it will extract from 0th index to stop index. We can omit both start and stop, in that case, we need to provide at least colon (t[:]). If we don’t provide step value default, the value will be 1.

Ex:

t = (1,2,3,4,5,’i’,’hi’,10.5)

In this example, we would want to extract elements “1,2,3,4”.

t1 = t[0:4]

Suppose we want to extract elements “3,4,5,’i’,’hi’,10.5”

t1 = t1[2:8] or t1[2:]

Suppose we want to extract elements “2,3,4,5,’I’,’hi’ ” (using reverse index)

t1 = t[-7:-1:]

Suppose we want to reverse a tuple

t1 = t[::-1]

Nested Tuples

We can declare tuple in a tuple, i.e., nested tuples.

t = (1,2, (3,4,5),6,7,(‘a’,’b’,’c’))

Consider nested tuple as another tuple and its index also starts from 0.

We can access nested tuples elements as below:

  1. Find nested tuple index in main tuple
  2. Find nested tuple index

Ex:

In the example below, we want extract “3” from nested tuple. Here, the main tuple index is “t[2]”, and nested tuple “(3,4,5)” index is “0”. So, the final expression is “t[2][0]”.

In the second example, we extracted “b” from nested tuple using expression “t[5][1]”.

Length

This method returns number of elements in tuple.

Syntax:

len(variable)

Access tuple by element using loop

Syntax:

For variable in tuple variable:

print(variable)

Repetition

This is useful when we want to repeat the tuple for given number.

Syntax:

variable * number of times repetition

Example:

t * 2

Here, the tuple is repeated 2 times, as shown below.

Concatenation

This concatenates or combines 2 tuples.

Syntax:

t3 = t1 + t2

Search element in a tuple

This return “True” if element found in tuple else return “False”.

Syntax:

Element in tuple
Element not in tuple

Index

This method is used to find the index of element in tuple. If found returns “index of the element” else value error exception is raised.

Syntax:

variable.index(element, beg=0,end=len(string))

Count

This method is used to count occurrence of element in tuple.

Syntax:

variable.count(element)

Delete tuple

We can’t remove individual elements from tuples since it is immutable. But we can delete entire tuple.

Syntax:

del variable

In the above example, we declared tuple t and printed t. After that, we deleted a tuple using “del t” and tried to print tuple. It throws nameerror exception because “tuple t” doesn’t exist.

Minimum

This method is used to find minimum value of element in a tuple.

Syntax:

min(variable)

Maximum

This method is used to find minimum value of element in a tuple.

Syntax:

max(variable)

Compare 2 tuples

This method is used to compare elements of 2 tuples.

  1. Return 0 if elements of both tuples are equal
  2. Return 1 if elements of the first tuple are greater than the second tuple
  3. Return -1 if elements of the first tuple are less than the second tuple

Syntax:

cmp(tuple1, tuple2)

If elements types are mismatched, then element is converted to int type.

Tuples are compared index by index. The 1st element of the 1st tuple is compared to the 1st element of the 2nd tuple. If they are not equal, this is the result of the comparison, else the 2nd element is considered, then the 3rd element, and so on.

Conclusion

Tuple is immutable data type, and any operation we perform should be stored in another tuple variable. It is faster compared to the other data types (ex: list, dictionary). Since tuple is immutable in our program, the data is not going to change the entire software life cycle, we can use tuple like system configuration data.

The above is most commonly and generally used operation on tuple. If we want to check what all the operations are supported for tuple, type dir(tuple) on interpreter and hit enter. It will display all methods/function. If we want to check documentation for tuple method/function, type help(tuple) and hit enter. ]]> How to change time format in Wireshark https://linuxhint.com/change-time-format-wireshark/ Sun, 15 Nov 2020 08:13:46 +0000 https://linuxhint.com/?p=76761 Wireshark is a popular network capturing and analysis tool. There are many options for doing better and quick analysis. One of them is using the time format in Wireshark. Let’s understand for this article how to use the time format in Wireshark.

Where is time in Wireshark capture?

Let’s open one saved capture to understand the time option in Wireshark. Now we can see below screenshot that the second column is a time-related column.

Where is “Time Display Format” in Wireshark capture?

Now we can check what the “Time Display Format” in Wireshark is.
Go to View->Time Display Format. Here is the output

Meaning of each option:

To understand this, we will select one option and see the effect on Wireshark capture. Let’s label each option one number for easy understanding.

As we see, there are two sections

The First 1 to 10 options are for time display format, and the next 1 to 7 options are for the time unit.

Let’s keep next option 1 (See below screenshot)

constant and make changes for the first 1-10 options.

Option 1:

Now we will see the date and time for each packet of Wireshark. Here is the output screen

Option 2:

Now we will see the year, day of the year, and time of the day. Here is the output screen

Option 3:

After selecting this option, we can see only the Time of the Day. No year is shown.

See the below screenshot.

Option 4:


This option enables time in second in Epoch Time style. Here is the screenshot.

Option 5:


After selecting this option, we will see the first packet of captured time is set to 0.00 second, and after how many seconds the next packet was captured. So we will see the time will be increasing.

See the below screenshot.

Option 6:


This shows the time for each packet with reference to the previous capture packet. So we will see time as “Time delta from previously captured frame” second for the current packet.

See the below screenshot.

Option 7:


This option shows the time as “Time delta from previously displayed frame” second for the current packet. Actually, “option 6” and “option 7” are the same for maximum times. That’s why we do not see any differences.

See the below screenshot.

Option 8:


This shows the time as UTC [Coordinated Universal Time] Date and Time of the day. This option is almost the same as “option 1,” but the Time of day is different.

See the below screenshot.

Option 9:


Now we will see UTC year, day of the year, and time of the day.

Here is the output screen

Option 10:


After selecting this option, we can see only UTC Time of Day. No year is shown here.

We are done with the first set of options. Now, let’s see how the time unit affects the Wireshark packet time.

Keep below time format constant

Option 1:


This gives the default Date and Time from capture.

See the below screenshot.

Option 2:


Now see the difference between option1 and this option. We can see time is shown till the second.

Check the below screenshot.

Option 3:


This option shows “Tenth of Second” for time.

Check the below screenshot.

Option 4:


This option shows “Hundredths of Second” for time.

Check the below screenshot.

Option 5:


This shows the millisecond part after second. Look at the below screenshot.

Option 6:


Now we can see a microsecond part of the time. See the below screenshot.

Option 7:


This option enables a microsecond part of the time. See the below screenshot.

Check Box


As our current Time Format is already having Hours and Minutes, so it does not affect.
So, we can play a combination of all these options.

Try one random combination:

Let’s see the effect of the below combination

Output [Look at Day Time column]:

Conclusion:

Now we know the time formats and units, we may think, what is the use of all these different options? This help does Wireshark capture analysis. We may need a different time scale to see many factors from Wireshark captures. So, it’s all about quick and better Wireshark capture analysis.

]]>
How Memset Function is Used https://linuxhint.com/memset_function/ Sun, 15 Nov 2020 03:47:47 +0000 https://linuxhint.com/?p=76575

In C, the memset() function is used to set a one-byte value to a memory block byte by byte. This function is useful for initialization of a memory block byte by byte by a particular value. In this article, we will see in detail how this function can be used. So, let’s get started.

Header File:

1
string.h

Syntax:

1
void *memset(void *str, int ch, size_t n)

This function sets the first bytes of the memory block pointed by str by ch.

Arguments:

The function takes 3 arguments:

  1. str: This is the pointer of the memory location where the memory will be set. This is a void pointer, so we can set any type of memory block, but the memory will be set byte by byte.
  2. ch: This is the value that is to be copied to the memory block. This is an integer value, but it is converted to an unsigned character before copied.
  3. n: This is the number of bytes in the memory block which is set.

Return values:

memset() returns the first address of the memory block from where it starts to set the value.

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Example1.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    char str[30] = "ABCD EFGH";  
     
    printf("Before memset => %s",str);  
     
    memset(str,'x',3);  
     
    printf("\nAfter memset => %s\n",str);  
     
    return 0;  
}


In Example1.c, we have declared one character array of size 30. Then we have initialized it with the string “ABCD EFGH.” In the memset function, we have passed 3 arguments str, ‘x’ and 3. So, the memory block pointed by str will be reset the first 3 characters by ‘x.’ After memset, when we print the memory, we will get “xxxD EFGH.”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Example2.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    char str[30] = "ABCD EFGH";  
     
    printf("Before memset => %s",str);  
     
    memset(str+4,'x',3);  
     
    printf("\nAfter memset => %s\n",str);  
     
    return 0;  
}


In Example2.c, we have passed str+4 to memset function. So, it reset the memory after the 4th location of str.  After memset, when we print the memory, we will get “ABCDxxxGH.”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Example3.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    int arr[5],i;  
     
    memset(arr,10,5*sizeof(arr[0]));  
     
    printf("\narr Elements => \n");  
     
    for(i=0;i<5;i++)  
        printf("%d\t",arr[i]);  
     
    printf("\n");
    return 0;
}


In Example3.c, we have declared an integer array of size 5 and trying to initialize it by 10. But from the output, we have seen that the array is not initialized by 10; instead, we have got the value “168430090”. This is because the integer value is greater than one byte and the memset function converts the value to an unsigned character before copied. Now, we will see how we will get the value “168430090”.


The binary representation of 10 is 00000000 00000000 00000000 00001010.

When integer converted to unsigned char, the lower 1 byte is considered. So, when 10 is converted to unsigned char, it’s a binary representation is 00001010.

memset() function sets the memory location byte by byte. So, a total of 4 bytes will be: 00001010 00001010 00001010 00001010.

The decimal value of the binary representation of 4 bytes is 168430090.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Example4.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    int arr[5],i;  
     
    memset(arr,0,5*sizeof(arr[0]));  
     
    printf("\narr Elements => \n");  
     
    for(i=0;i<5;i++)  
        printf("%d\t",arr[i]);  
     
    printf("\n");
    return 0;
}


In Example4.c, we have initialized the integer array by 0. All bits of the binary representation of 0 is 0. So the array is initialized by 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Example5.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    int arr[5],i;  
     
    memset(arr,-1,5*sizeof(arr[0]));  
     
    printf("\narr Elements => \n");  
     
    for(i=0;i<5;i++)  
        printf("%d\t",arr[i]);  
     
     printf("\n");
     return 0;
 
}


In Example5.c, we have initialized the integer array by 0. All bits of the binary representation of -1 is 1. So the array is initialized by -1.

Conclusion:

In this article, we have seen using the memset function how we can initialize or set the value of a memory block efficiently. We can set any character and 0 or -1 as an integer value to a memory block. Memset function is faster to set a large chunk of contiguous memory in comparison with simply setting the location using a loop.

]]>
Python String Operations https://linuxhint.com/python_string_operations/ Fri, 13 Nov 2020 21:23:22 +0000 https://linuxhint.com/?p=76593

In this article, we are going to discuss operations on strings. As we know in python, a string is an immutable data type (read-only). This can be declared in single quotes (s=’ ’) or double quotes (s=” ”), or triple quotes (s=’’’ ’’’ or s=””” “””)

How to enter into the python interpreter

Open Linux terminal and type python and hit enter so we will see python interpreter. For python3+ version, type python3. The following info we are going to see on the terminal. If we want to check the python version, the command is “python -v.”

Output:

Python 3.5.0 (default, Sep 20 2019, 11:28:25)

[GCC 5.2.0] on linux

Type "help", "copyright", "credits" or "license" for more information.

>>>

The following operations can be performed on the string

String Slice

This is useful when we want only part of the string.

Note: string index always starts from 0. A string can be traversed in forward and as well as reverse direction (using the negative index).

Ex: s =”Good morning”

Forward traverse index: [0,1,2,3]

reverse traverse index :[..,-3,-2,-1]  here s[-1]=”g”, s[-2]=”n”, s[-3]=”I”,

syntax: variablename[start:stop:step].

Here stop is excluded. If we provide only a start, it will extract all the characters from start to end. If we provide only a stop, it will extract from the 0th index to stop. We can omit both starts and stop; in that case, we need to provide at least colon (s[:]). If we don’t provide a Step value, the default value is 1.

Ex: s1 = ”Good morning”.

In this example, we want to extract “good”.

s2 = s1[0:4]


Suppose we want to extract “ood mor”

s2 = s1[1:8]


Suppose we want to extract “ning”(using the reverse index)

s2 = s1[-5:-1:]


Suppose we want to reverse a string

s2 = s1[::-1]

Length

This method returns the number of characters in the string.

syntax: len(string)

Concatenation

This concatenates or combines two strings.

syntax: s3 = s1 + s2

Uppercase

This method converts all the characters in the string to upper case.

syntax: string.upper()

s1 = ‘Good morning’

s2 = s1.upper()

Lowercase

This method converts all the characters in the string to lower case.

syntax: string.lower()

s1 = ‘Good MorninG’

s2 = s1.lower()

Strip

This method strip/delete the value from the string provided as a parameter. The default parameter is space.

There 3 types of strips:

  1. lstrip() : This strips only the left side of the string.
  2. rstrip() : This strips only the right side of the string.
  3. strip() : This strips entire string.

Search substring in a string

This return “True” if substring found in string else returns False. The membership operators “in” and “not in” is used to check this.

syntax: substring in a string

Startswith

This method is used to check if a string starts with a substring. It returns True if the string starts with substring else return False.

syntax: s.starsiwth(substring)

Endswith

This method is used to check if a string ends with a substring. It returns “True” if the string ends with substring else return False

syntax: s.endsiwth(substring)

Index

This method is used to find the index of the substring in a string. If found, returns start character index of substring else value error exception is raised.

syntax: string.index(substing, beg=0,end=len(string))

Find

This method is used to find the index of a substring in a string. If found, returns start character index of substring else -1 value returned.

syntax: string.find(substing, beg=0,end=len(string))

Count

This method is used to count the occurrence of a substring in a string.

syntax: string.count(substring)

Swap case

This method swap/interchange the case of a string.

syntax: string. Swapcase()

Capitalize

This method capitalizes the first letter of string

syntax: string.capitalize()

Find minimum/maximum alphabetical character in the string

syntax: min(string), max(string)

Replace

This method replaces the occurrence of a substring with another string. If max provided that many times it will replace

syntax:  string. replace (old substring, newstring, max)

Split

This method Split the string based on the parameter provided. It returns a list of words if a split parameter found other returns string as a list.

In 1st example, the split character is space, and it is found in a string. It returns a list of words

In 2nd example, the split character is _, and it did not found in the string. It returns the same string as the list.

Check string contain alphanumeric characters

This method returns “True” if all characters in a string are alphanumeric; otherwise, False

syntax: string.isalnum()

Check string contains alphabetic characters

This method returns “True” if all characters in a string are alphabetic; otherwise, False

syntax: string.isalpha()

Check string contains only digits

This method returns “True” if all characters in a string are digits; otherwise, False

syntax: string.isdigit()

Check string contain all lowercase characters

This method returns “True” if all characters in a string are lowercase; otherwise, False

syntax: string.islower()

Check string contain all uppercase characters

This method returns “True” if all characters in a string are uppercase; otherwise, False

syntax: string.isupper()

Check string contains only space

This method returns “True” if all characters in a string are spaces; otherwise, False

syntax: string.isspace()

Join

This method takes all items in a sequence (list, tuple, dict) and joins as a single string based on parameter. All items should be a string.

syntax: parameter.join(sequence)


Here the sequence is a list, and all items are joined using space and # parameter.

Conclusion

The string is an immutable datatype, and any operation we perform should be stored in another string variable. The above are the most common and generally used operation on string.

If we want to check what are all operations are supported for string type dir(str) on an interpreter and hit enter. It will display all methods/functions if we want to check the documentation for string method/function type help(str) and hit enter.

]]>
How to Use Wireshark to Search for a String in Packets https://linuxhint.com/use_wireshark_search_string_packets/ Sat, 07 Nov 2020 13:58:42 +0000 https://linuxhint.com/?p=75906

In this article, you will learn how to search for strings in packets using Wireshark. There are multiple options associated with string searches. Before going further in this article, you should have a general knowledge of Wireshark Basic.

Assumptions

A Wireshark capture be in one state; either saved/stopped or live. We can perform string search in live capture also but for better and clear understanding we will use saved capture to do this.

Step 1: Open Saved Capture

First, open a saved capture in Wireshark. It will look like this:

Step 2: Open Search Option

Now, we need a search option. There two ways to open that option:

  1. Use the keyboard shortcut “Ctrl+F”
  2. Click “Find a packet” either from the outside icon or go to “Edit->Find Packet”

Check out the screenshots to view the second option.

Whichever option you use, the final Wireshark window will look like the screenshot below:

Step 3: Label Options

We can see multiple options (dropdowns, checkbox) inside the search window. You can label these options with numbers for easy understanding. Follow the screenshot below for numbering:

Label1
There are three sections in the dropdown.

  1. Packet list
  2. Packet details
  3. Packet bytes

From the below screenshot, you can see where these three sections in Wireshark are located:

Selecting section a/b/c means that the string will be done in that section only.

Label2
We will keep this option as the default, as it is the best for common searching. It is recommended to keep this option as the default unless it is required to change it.

Label3
By default, this option is unchecked. If “Case sensitive” is checked, then the string search will only find exact matches of the searched string. For example, if you search for “Linuxhint” and Label3 is checked, then this will not search for “LINUXHINT” in Wireshark capture.

It is recommended to keep this option unchecked unless it is required to change it.

Label4
This label has different types of searches, such as “Display filter,” “Hex value,” “String,” and “Regular Expression.” For the purposes of this article, we will select “String” from this dropdown menu.

Label5
Here, we need to enter the search string. This is the input for the search.

Label6
After the Label5 input is given, click the “Find” button to trigger the search.

Label7
If you click “Cancel,” then the search windows will close, and you need to return to follow Step 2 to get this search window back.

Step 4: Examples

Now that you understood the options for searching, let us try out some examples. Note that we have disabled the coloring rule to see the search packet we selected more clearly.

Try1 [Options combination used: “Packet List” + “Narrow & Wide” + “Unchecked Case Sensitive”+ String]

Search String: “Len=10”

Now, click “Find.” Below is the screenshot for the first click on “Find:”

As we have selected “Packet list,” the search was performed inside the packet list.

Next, we will click the “Find” button again to see the next match. This can be seen in the screenshot below. We did not mark any sections to allow you to understand how this search happens.

With the same combination, let us search the string: “Linuxhint” [To check not found scenario].

In this case, you can see the yellow-colored message at the left-bottom side of Wireshark, and no packet is selected.

Try2 [Options combination used: “Packet details” + “Narrow & Wide” + “Unchecked Case Sensitive”+ String]

Search String: “Sequence number”

Now, we will click “Find.” Below is the screenshot for the first click on “Find:”

Here, the string found inside “packet details” was selected.

We will check the “Case sensitive” option and use the search string as a “Sequence Number,” keeping the other combinations as is. This time, the string will match the exact “Sequence Number.”

Try3 [Options combination used: “Packet bytes” + “Narrow & Wide” + “Unchecked Case Sensitive”+ String]

Search String: “Sequence number”

Now, click “Find.” Below is the screenshot for the first click on “Find:”

As expected, the string search is happening inside the packet bytes.

Conclusion

Performing a string search is a very useful method that can be used to find a required string inside of a Wireshark packet list, packet details, or packet bytes. Good searching makes analysis of large Wireshark capture files easy.

]]>
How to Capture Wi-Fi Traffic Using Wireshark https://linuxhint.com/capture_wi-fi_traffic_using_wireshark/ Sat, 07 Nov 2020 10:16:42 +0000 https://linuxhint.com/?p=75862

In this article, you will learn how to capture wireless frames using Wireshark in Linux (Example: Ubuntu. To follow this article, first, you should learn the basics of WireShark in the Wireshark Basic article, and then you can come back here.

There are some steps to be followed to achieve this.

Setup Check

Below are the requirements for capturing Wi-Fi packets using Wireshark.

Wi-Fi Interface

To check whether you meet this requirement, open the terminal using the shortcut Alt+Ctrl+T and run the command “iwconfig.” This output should show if there is an operable Wi-Fi interface. The following screenshot shows the output of this command:

In this example “wlp2s0” is the interface name for the Wi-Fi card.

  • “IEEE 802.11” is the indication for the Wi-Fi interface.
  • By default, the mode is “Managed,” which means that it is a client or station mode.

Support for Monitor Mode

The Wi-Fi card must support monitor mode to be able to sniff out wireless packets. This is a must, or you cannot sniff wireless packets using Wireshark. Open the terminal and run the command “iw phy0 info” or “iw list.” There is a huge list of information available here, but we just have to check the section for “monitor.” If the device does not support monitor mode, then it will not be possible to sniff the wireless packet using Wireshark.

Check Wireshark Software

Open the terminal and run the command “wireshark –version.” If Wireshark is installed, then there should be a version name with many details, as in the following screenshot:

If it is not installed, then use the commands “apt-get update” and “apt-get install wireshark” to install Wireshark on your system.

Configuring Monitor Mode

In previous sections, you saw that the Wi-Fi interface default mode is “managed.” To capture a wireless packet, we need to convert the “managed” mode to “monitor” mode. There are different commands that you can use, but to use a simple method first, we will try using the “iwconfig” command to create monitor mode.

Let us assume that the name of the Wi-Fi interface is “wlp2s0,” as shown in the screenshot.

Step 1: Enter Superuser Mode

First, enter into superuser mode; otherwise, we will get permission to do this.

Command: “su

Step 2: Create Monitor Mode

Command: “iwconfig wlps20 mode monitor

Output: If the interface is up and active, you will get the “Device or resource busy” error.

So, make interface down using the following command.

Command: “ifconfig wlsp2s0 down

Then, execute the first command again.

Finally, check whether the interface is in monitor mode using the “iwocnfig” command.

Here is the screenshot to explain all the above steps:

Step 3: Configure Wi-Fi Sniffing Channel

In wireless protocol, there are two radio frequency bands:

  1. 5GHz [Frequency range is 5180MHz – 5825MHz]
  2. 2.4GHz [Frequency range is 2412MHz – 2484MHz]

Wiki link for WLAN channels list: https://en.wikipedia.org/wiki/List_of_WLAN_channels

If your wireless card supports 1 and 2, that means that the Wi-Fi card can sniff both bandwidth configured channels. Let us see what our card supports.

Using the command “iw list,” we can check this capability. We are looking for the section below in the command output screenshot:

As yu can see in the above list, this Wi-Fi chip supports only 2.4Ghz [Check the frequency range].

Each frequency is known as channel number. For example, 2412MHz is considered channel 1 [Shown in [] ].

Now, we need to configure one channel for our monitor mode interface. Let us try to set channel 11 [frequency is 2462MHz].

Command: “iwconfig wlp2s0 channel 11

If above command outputs an error, this makes the interface up [“ifconfig wlp2s0 up”] and then executes the “iwconfig wlp2s0 channel 11” command. Finally, execute the “iwconfig” command to ensure that the channel is set up properly.

The following screenshot explains the steps given above:

Step 4: Launch Wireshark and Start Capturing

Now, we are all set to capture wireless packets. You can start Wireshark in the background using the following command:

In the startup window of Wireshark, you should see the following screen. Here, you can see a list of interfaces.

Next, choose your monitor mode interface, which is “wlp2s0.” Select this interface and then double-click on it.

You can see that live capturing is currently going on.

The following include some hints about wireless packets:

You should see the protocol section, which generally shows 802.11, which is wireless IEEE standard.

You should also see the “Beacon,” “Probe Request,” and “Probe Response” frames under the info section of any frame.

If you wish to save the capture and check it later, then select “save” or “save as” and save it for later analysis.

As long as the interface is in monitor mode you can capture wireless packet. Remember if you reboot the system the wireless interface will come up as “Managed” mod again.

Conclusion

In this article, you learned how to capture wireless packets using Wireshark in Linux. This is very easy to do in Linux using the built-in Wi-Fi card without installing any extra third-party software. You can make a shell script containing all these commands and run that single shell script to configure your system’s Wi-Fi card as monitor mode, set the preferred channel, and start using Wireshark.

]]>
Static in C Programming https://linuxhint.com/static_c/ Tue, 27 Oct 2020 23:13:14 +0000 https://linuxhint.com/?p=74316 In this tutorial, we will explain the static keyword by applying it in variables and functions. Static is a keyword used in C programming, and it can be applied by using the following syntax:

static {data type} {variable name}

Static local variables

When a variable in a function is static, the variable preserves its value between function calls.

//Example1.c  
 
#include<stdio.h>  
 
int fun1()  
{  

    int count=0;  
    count++;  
    return count;  
}  
 
int fun2()  
{  
    static int count=0;  
    count++;  
    return count;  
}  
 
int main()  
{  
    printf("fun1 1st call returns : %d\n",fun1());  
    printf("fun1 2nd call returns : %d\n\n",fun1());  
 
    printf("fun2 1st call returns : %d\n",fun2());  
    printf("fun2 2nd call returns : %d\n",fun2());  
 
    return 0;  
}


In Example 1.c, we have two functions: fun1() and fun2(). In fun1(), we declare one variable (count) and initialize it to 0. Then, we increment the count variable and return the resulting value. Using main(), we call fun1() twice, and each time, a value of 1 is returned because the count variable is cleared when the call to fun1() is completed. In fun2() we declared the count variable as a static variable. Therefore, its value is preserved. Using main(), we call fun2() twice: the first time, a value of 1 is returned, and the second time, a value of 2 is returned.

Static global variables

A static global variable behaves in the same way as other global variables, but it cannot be accessed from another C program.

Static functions

In C, functions are global by default. However, if we declare a static function, then the function is local and cannot be accessed from another C program.

Initialization of static variables

If a static variable is not explicitly initialized, then it is initialized as 0.

//Example2.c  
 
#include<stdio.h>  
 
int main()  
{  
    static int i;  
     
    printf("Value of i : %d\n",i);  
 
    return 0;  
}


In Example2.c, we declared a static variable i that is not initialized. However, because the variable is static, it is automatically initialized to 0.

It is important to note that a static variable must be initialized by a constant literal; we cannot use a function’s return value to initialize a static variable.

//Example3.c  
 
#include<stdio.h>  
 
int fun1()  
{  
    return 5;  
}  
 
int main()  
{  
    static int i = fun1();  
    printf("Value of  i : %d\n",i);  
    return 0;  
}


In Example3.c, we try to initialize a static variable by using the return value of fun1(). However, as you can see, an error is returned when the code is compiled.

Summary

The lifetime of a static variable and the lifetime of the program are equal.

If a static variable is not initialized, then it will take on a default value of 0.

Neither a global static variable nor a static function is accessible from a program other than the one in which it was defined.

]]>
rand() Function in C Language https://linuxhint.com/rand-function-in-c-language/ Thu, 22 Oct 2020 03:27:13 +0000 https://linuxhint.com/?p=72619 In the C language, the rand() function is used for Pseudo Number Generator(PRNG). The random numbers generated by the rand() function are not truly random. It is a sequence that repeats periodically, but the period is so large that we can ignore it. The rand() function works by remembering a seed value that is used to compute the next random number and the next new seed. In this article, we are going to discuss in detail how random numbers can be generated using the rand() function. So, let’s get started!

Header File:

stdlib.h

Syntax:

int rand (void)

Return values:

This function returns the next pseudo-random number in the series. The range value of the number series is between 0 and RAND_MAX. RAND_MAX is a macro defined in stdlib.h header file, whose value is the maximum value, which can return by rand() function. The value of RAND_MAX is greater but not less than 32767 depending on the C libraries.

//Example1.c  
     
#include<stdio.h>  
#include<stdlib.h>  
     
int main()  
{  
     
    int i;  
     
    printf("10 Random Numbers =>\n");      
         
    for(i=0;i<10;i++)  
    {  
        printf("%d ",rand());  
    }  
     
    printf("\n");  
    return 0;
}


In Example1.c, we call the rand() function in each iteration of for loop and print the return value of the function. The value sequence of the rand() function is the same each time we run the program. By default, the seed of the rand function is set to 1.

We can set the seed for the rand function using the srand() function. The seed can be set only once, and before the first time rand() function call.

srand() function:

Header File:

stdlib.h

Syntax:

int srand (unsigned int seed)

Arguments:

This function takes 1 argument

seed: An integer value used as a seed for a new series of pseudo-random numbers.

Return values:

None

//Example2.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
 
    srand(time(0));  
 
    printf("10 Random Numbers =>\n");      
     
    for(i=0;i<10;i++)  
    {  
        printf("%d ",rand());  
    }  
 
    printf("\n");  
    return 0;  
}


In Example2.c, we have used the srand() function to set the initial seed of the random number sequence generated by rand() function. Each time the program is run, a different sequence is generated. In srand(), time(0) function (declared in time.h header file) is used as a seed. This time(0) function returns the number of seconds elapsed since the epoch (00:00:00, January 1, 1970). This still may produce the same sequences if you run the program in the same second.

//Example3.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
 
    srand(time(0));  
 
    printf("10 Random Numbers between 1 and 10=>\n");      
     
    for(i=0;i<10;i++)  
    {  
        printf("%d ",(rand() %10) + 1);  
    }  
 
    printf("\n");  
    return 0;  
}


In Example3.c we have seen how random numbers can be generated between 1 and 10.

//Example4.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i,max,min;  
 
    printf("Enter Min value => ");  
    scanf("%d",&min);  
    printf("Enter Max value => ");  
    scanf("%d",&max);  
     
    if(min>max)  
    {  
        printf("Min value is greater than max value\n");  
        return 0;  
    }  
 
    srand(time(0));  
     
 
    printf("10 Random Numbers between %d and %d=>\n",min,max);    
     
    for(i=0;i<10;i++)  
    {  
        printf("%d ",(rand() % (max - min +1)) + min);  
    }  
 
    printf("\n");  
    return 0;  
}


In Example4.c we have taken the range from the user and generated a random number within this range. The formula is: rand() % (max – min +1)) + min

//Example5.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
 
    srand(time(0));  
 
    printf("10 Random Numbers between 0.0 and 1.0=>\n");  
     
    for(i=0;i<10;i++)  
   {  
        printf("%f ",((float)rand() /RAND_MAX));  
    }  
 
    printf("\n");  
    return 0;  
}


In Example5.c, we have seen how we can generate random numbers between float 0.0 and 1.0 The formula is: (float)rand() /RAND_MAX)

//Example6.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
    float max,min;  
 
    printf("Enter Min value => ");  
    scanf("%f",&min);  
    printf("Enter Max value => ");  
    scanf("%f",&max);  
 
    if(min>max)  
    {  
        printf("Min value is greater than max value\n");  
        return 0;  
    }  
 
    srand(time(0));  
 
    printf("10 Random Numbers between %f and %f =>\n",min,max);    
     
    for(i=0;i<10;i++)  
    {  
        printf("%f ",min + ((float)rand() /(RAND_MAX/(max - min))));  
    }  
 
    printf("\n");  
    return 0;  
}


In Example6.c, we have taken the range from the user and generated a random number within this range (both inclusive). The formula is: min + ((float)rand() /(RAND_MAX/(max – min)))

Conclusion:

In this article, we have learned how random numbers can be generated using the rand() and srand() function. There are no guarantees about the quality of the random numbers generated by the rand function, but it is good enough for casual use. ]]> How to use memcpy function in C language? https://linuxhint.com/memcpy_function_c_programming/ Thu, 08 Oct 2020 10:44:01 +0000 https://linuxhint.com/?p=70317 In the C language memcpy() function is used to copy a block of memory from one location to another. In this article, we are going to discuss in detail how the memcpy() function is used. So, let’s get started.

Header File:

string.h

Syntax:

void * mempcpy (void *dest, const void *src, size_t size)

Arguments:

The function takes 3 arguments:

  1. dest :
  2. This is a starting pointer of a memory block where the memory block pointed by src (2nd argument) will be copied. The pointer is declared as void, so any type of memory block can be copied.

  3. src :
  4. This is a starting pointer of the source memory block from where the memory block will be copied. The pointer is declared as void, so any type of memory block can be copied.

  5. size :
  6. This is the size of the memory block in bytes.

The value of the two pointer dest and src should be in such a way that two memory blocks do not overlap. The size of memory blocks of source and destination must be at least of size (3rd argument) bytes to avoid overlapping situations. If the two memory blocks are overlapped then the behavior of the memcpy() function is undefined. When there is a possibility of overlapping, you can use the memmove() library function where overlapping is well defined. memmove() function is slower compared to memcpy() function.

Due to the value of size, if the source or destination is accessed beyond their buffer length then the behavior of the memcpy() function is undefined.

The memcpy() function does not check to terminate ‘\0’ character.

Return values:

This function returns the value of destination address dest. As the value of dest is already available so, it need not to store in any variable.

Examples:

   //Example1.c  
     
   #include<stdio.h>  
   #include<string.h>  
     
   int main()  
   {  
       char src[] = "Hello";  
       char dest[13];  
       
      memcpy(dest,src,6);      
       
      printf("dest after first memcpy() => %s\n",dest);  
   
      memcpy(dest+sizeof(src)-1," world!",8);  
   
      printf("dest after second memcpy() => %s\n",dest);  
   
      return 0;  
  }

In Example1.c we have declared two-character array src and dest. The size of the src is 6 and the dest is 13. First, we copied 6 characters ‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’ from src to dest ( Line 11 ). In the second memcpy() function copied 8 characters ‘ ’, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘!’, ‘\0’ to the dest after 5 characters ( Line 15 ). Pictorially we can represent this as follows:

//Example2.c  
 
#include<stdio.h>  
#include<string.h>  
 
int main()  
{  
    typedef struct student  
    {  
        char *name;  
        int id;  
        int age;  
    }std;  
 
    std student1; // Declare student1 of type std  
    std student2; // Declare student2 of type std  
     
    // Assigning the value of sudent1  
    student1.name = "Bamdev Ghosh";  
    student1.id = 1105;  
    student1.age = 30;  
 
    printf("Student1:\n\tName : %s\n\tid : %d\n\tage : %d\n",student1.name,
    student1.id,student1.age);  
     
    // Copy student1 to student2      
    memcpy(&student2, &student1, sizeof(student1));  
     
    printf("\n\nAfter memcpy:");  
    printf("\n\nStudent2:\n\tName : %s\n\tid : %d\n\tage : %d\n",
    student2.name,student2.id,student2.age);  
 
    return 0;  
}

In Example2.c we have declared two structure student1 and student2 (Line 15 and 16). First, we initialize student1 (Line 19, 20, 21). After that, we use memcpy to copy data from student1 to student2.

Conclusion:

In this article, we have learned how to use the memcpy function. We have seen that this function can be used for any type of memory block but this function has some limitations. So, you have to use this function carefully. ]]> String Length in C Language https://linuxhint.com/string_length_c_language/ Fri, 02 Oct 2020 17:45:59 +0000 https://linuxhint.com/?p=69761 A string in C language is an array of characters that is terminated with a null character (\0). The string length is the number of characters in a string. In the string length ‘\0,’ a character is not counted.

In the example shown above, the length of the string str is 6.

In this tutorial, first, we will show how to use a user defined function to calculate length of a string, and then we will show you a built-in library function strlen(). We also show you the uses of the sizeof operator for string literals.

String Length Using User Defined Function

You can write a user defined function which returns the number of characters in a string.

//Example1.c  
#include<stdio.h>  
 
int stringLength(char *str)  
{  
    int i=0;  
     
    while(str[i] != '\0') i++;  
     
    return i;  
}  
 
int main()  
{  
    char str[30]= "STRING";  
     
    printf("Length of the string str is => %d\n",stringLength(str));  
         
    return 0;  
}

Here, we iterate the while loop from i = 0 until we do not encounter the ‘\0’ character. The value of i is increased by 1 in each iteration of the while loop. When the loop ends, the value of i is the length of the string.

String Length Using Built-In Library Function

The built-in library function strlen() can also be used to determine string length.

strlen() function:

Header file:

string.h

Syntax:

size_t strlen (const char *str)

Argument: This function takes an argument of the type pointer to char.

Return value: This function returns the length of the string str. Note that size_t is just an alias of an unsigned integer.

//Example2.c  
#include<stdio.h>  
#include<string.h>  
 
int main()  
{  
    char str1[30]="STRING ARRAY";  
    char *str2;  
    char *str3;  
     
    str2 = str1;  
    str3 = "STRING POINTER";  
     
    printf("Length of the string str1 is => %ld\n",strlen(str1));  
    printf("Length of the string str2 is => %ld\n",strlen(str2));  
    printf("Length of the string str3 is => %ld\n",strlen(str3));  
    printf("Length of the string "STRING LITERALS" is => %ld\n",strlen("STRING LITERALS"));  
         
    return 0;  
}

Here, we pass string array, string pointer, and string literal to the strlen function, and the function returns the length of the string.

String Length Using sizeof Operator

We also can use the sizeof operator for string length (only for string literal). But, we have to subtract 1 from the value returned by this operator, because it also counts the’\0’ character. For array and pointer, the sizeof operator returns the allocated size of the array and the pointer, respectively.

//Example3.c  
#include<stdio.h>  
 
int main()  
{    
    char str1[30] = "STRING";  
    char *str2 =str1;  
     
    printf("Length of "STRING" is => %d\n",(sizeof("STRING") - 1));  
    printf("Allocated size of the str1 array is => %d\n",sizeof(str1));  
    printf("Size of the str2 pointer is => %d\n",sizeof(str2));  
         
    return 0;  
}

Here, in Line no 9, we pass the string literal “STRING” and get the size, including the ‘\0’ character. So, we subtract 1 and get the actual size of the string.

When we pass an array to the sizeof operator, it returns the allocated size of the array, which is 30, and when passing a character pointer, it returns the size of the pointer.

Conclusion

So, in this tutorial, we have shown you how string length can be calculated in various ways. You can use in your code whichever method is best suited for you.

]]>
String Comparison: C Programming https://linuxhint.com/comparing_strings_c_language/ Sat, 05 Sep 2020 11:15:18 +0000 https://linuxhint.com/?p=67511 A string in C language is an array of characters, which is terminated with a null character (\0). Using this property strings are compared.

Two strings can be compared in various ways. In this tutorial, first, we will see a user-defined function to compare two strings, and then we will see some built-in library functions which can be used to compare two strings very easily. So, let’s get started.

String comparison using a user-defined function :

We will write a function stringCompare() to compare strings. We traverse the strings and compare each character of the string until we reach the end of any one or both or one mismatched are found. If the traversal is reached to the end of both the strings, then the strings are matched; otherwise, strings are mismatched.

01. /*userDefinedFunction.c*/  
02.  
03. #include<stdio.h>    
04.    
05. int stringCompare( char str1[ ], char str2[ ] )    
06. {    
07.     int i=0;    
08.    
09.     while( str1[i] == str2[i] )    
10.     {    
11.         if( str1[i] == '\0' || str2[i] == '\0' )    
12.             break;    
13.         i++;    
14.     }    
15.    
16.     if( str1[i] == '\0' &&  str2[i] == '\0' )    
17.         return 0;    
18.     else    
19.         return -1;    
20.    
21. }    
22.    
23.    
24. int  main()    
25. {    
26.     char str1[30],str2[30];    
27.    
28.     printf("Enter the first string: ");  
29.     scanf("%[^\n]%*c",str1);  
30.     printf("Enter the second string: ");  
31.     scanf("%[^\n]%*c",str2);  
32.  
33.     if(stringCompare(str1,str2) == 0)  
34.         printf("The strings are equal \n");    
35.     else  
36.         printf("The strings are not equal \n");    
37.    
38.     return 0;    39.    }

Here we traverse the strings using while loop and a variable i. When characters are equal in the same position of both strings, the value of i is incremented by 1 (line 13). If characters are not equal (line 09) or we reach the end of the string (line 11), then the while loop is a break. After the while loop, we check both the string traversals are reached to the end or not (line 16). If the traversal is reached to the end of both strings, then the strings are equal otherwise not.

String comparison using built-in library functions :

The following library functions can be used for string comparison. All the functions are declared in the string.h header file.

strcmp() function :

This function compares two strings passed to the function.

Syntax:

int strcmp(const char *str1, const char *str2)

Return value: Return 0 if the strings are equal. Return a negative integer if the ASCII value of the first unmatched character of the first string is less than the second string. Return a positive integer if the ASCII value of the first unmatched character of the first string is greater than the second string. Some systems return difference of the ASCII value of first mismatched character and some systems return -1 if the ASCII value of the first unmatched character of the first string is less than the second string and return 1 if the ASCII value of the first unmatched character of the first string is greater than the second string.

Example Return Value Explanation
strcmp( “Hello World”,”Hello World” ) 0 Two strings are the same.
strcmp( “Hello”,”Hello\0 World” ) 0 Strings are compared till the character ‘\0’. The first string by default ends with ‘\0’, and the second string contains the ‘\0’ character after ‘Hello’.
strcmp( “Hello\0\0\0″,”Hello\0 World” ) 0 Strings are compared till the character ‘\0’.
strcmp( “Hello World”,”hello World” ) Negative integer ASCII value of the first unmatched character of the first string (‘H’) is less than the second string (‘h’)
strcmp(“hello World”,”Hello World” ) Positive integer ASCII value of the first unmatched character of the first string (‘h’) is greater than the second string (‘H’)

strncmp() function :

This function is similar to the function strcmp(), but here we have to specify how many bytes are compared by passing an extra argument to the function.

Syntax:

int strncmp(const char *str1, const char *str2, size_t n)

Return value: The function returns 0 if the first n characters of the two strings are equal; otherwise, it returns negative or positive integer depending on the sign of the differences between the first mismatched character’s ASCII value.

Example Return Value Explanation
strncmp( “Hello World”,”Hello World”,5 ) 0 First 5 characters are the same.
strncmp( “Hello”,”Hello\0 World”,5 ) 0 First 5 characters are the same.
strncmp( “Hello\0\0\0″,”Hello\0 World”,8 ) 0 ‘\0’ is after the first 5 characters in both strings. So, comparison is stopped after 5 not 8.
strncmp( “Hello World”,”hello World”,5 ) Negative integer ASCII value of the first unmatched character of the first string (‘H’) is less than the second string (‘h’)

strcasecmp() function :

This function is similar to the function strcmp(), but here the strings are not case sensitive.

Syntax:

int strcasecmp(const char *str1, const char *str2)

Return value: Same as strcmp(), but strings are treated as case-in-sensitive.

Example Return Value Explanation
strcasecmp( “Hello World”,”Hello World” ) 0 Two strings are the same.
strcasecmp( “Hello”,”Hello\0 World” ) 0 Strings are compared till the character ‘\0’. The first string by default ends with ‘\0’, and the second string contain the ‘\0’ character after ‘Hello’.
strcasecmp( “Hello World”,”hello World” ) 0 Strings are case-in-sensitive. So, “Hello World” and “hello World” are the same.

strncasecmp() function :

This function is similar to the function strncmp(), but here the strings are not case sensitive.

Syntax:

int strncasecmp(const char *str1, const char *str2)

Return value: Same as strncmp(), when strings are treated as case-in-sensitive.

Example Return Value Explanation
strncasecmp( “Hello World”,”Hello World”,5 ) 0 First 5 characters are the same.
strncasecmp( “Hello”,”Hello\0 World”,5 ) 0 First 5 characters are the same.
strncasecmp( “Hello\0\0\0″,”Hello\0 World”,8 ) 0 ‘\0’ is after the first 5 characters in both strings. So, comparison is stopped after 5 not 8.
strncasecmp( “Hello World”,”hello World”,5 ) 0 Strings are case-in-sensitive. So, “Hello” and “hello” are the same.

memcmp() function :

This function compares two memory blocks byte by byte. We have to pass two pointers of the memory blocks and the number of bytes to compare.

Syntax:

int memcmp(const void *str1, const void *str2, size_t n)

Return value: The function returns 0 if the two memory blocks (n bytes) are equal; otherwise, it returns the differences between the first mismatched pair of bytes (bytes are interpreted as unsigned char objects, then promoted to int).

Example Return Value Explanation
memcmp( “Hello World”,”Hello World”,5 ) 0 First 5 characters are the same.
memcmp( “Hello\0\0\0″,”Hello\0 World”,8 ) Negative integer The first 6 characters are the same, but the 7th character is different. Here comparison not stopped like strncmp() when getting ‘\0’ character.
memcmp( “Hello World”,”hello World”,11 ) Negative integer ASCII value of the first unmatched character of the first string (‘H’) is less than the second string (‘h’)

Example:

Following is the C code example of all the functions discussed.

01. /*stringCompare.c*/    
02.  
03. #include<stdio.h>    
04. #include<string.h>    
05.  
06. int main()    
07. {    
08. printf("strcmp( "Hello World","Hello World" ) => %d\n",strcmp( "Hello World","Hello World" ));    
09. printf("strcmp( "Hello","Hello\\0 World" ) => %d\n",strcmp( "Hello","Hello\0 World" ));    
10. printf("strcmp( "Hello World","hello World" ) => %d\n",strcmp( "Hello World","hello World" ) );    
11. printf("strcmp( "Hello\\0\\0\\0","Hello\\0 World" ) => %d\n",strcmp( "Hello\0\0\0","Hello\0 World" ));    
12.  
13. printf("\n---------------\n");    
14.  
15. printf("strncmp( "Hello World","Hello World",5 ) => %d\n",strncmp( "Hello World","Hello World",5 ));    
16. printf("strncmp( "Hello","Hello\\0 World",5 ) => %d\n",strncmp( "Hello","Hello\0 World",5 ));    
17. printf("strncmp( "Hello\\0\\0\\0","Hello\\0 World",8 ) => %d\n",strncmp( "Hello\0\0\0","Hello\0 World",8 ));    
18. printf("strncmp( "Hello World","hello World",5 ) => %d\n",strncmp( "Hello World","hello World",5 ));    
19.  
20. printf("\n---------------\n");    
21.  
22. printf("strcasecmp( "Hello World","Hello World" ) => %d\n",strcasecmp( "Hello World","Hello World" ));    
23. printf("strcasecmp( "Hello","Hello\\0 World" ) => %d\n",strcasecmp( "Hello","Hello\0 World" ));    
24. printf("strcasecmp( "Hello World","hello World" ) => %d\n",strcasecmp( "Hello World","hello World" ));    
25.  
26. printf("\n---------------\n");    
27.  
28. printf("strncasecmp( "Hello World","Hello World",5 ) => %d\n",strncasecmp( "Hello World","Hello World",5 ) );    
29. printf("strncasecmp( "Hello","Hello\\0 World",5 ) => %d\n",strncasecmp( "Hello","Hello\0 World",5 ));    
30. printf("strncasecmp( "Hello\\0\\0\\0","Hello\\0 World",8 ) => %d\n",strncasecmp( "Hello\0\0\0","Hello\0 World",8 ));    
31. printf("strncasecmp( "Hello World","hello World",5 ) => %d\n",strncasecmp( "Hello World","hello World",5 ));    
32.  
33. printf("\n---------------\n");    
34.  
35. printf("memcmp( "Hello World","Hello World",5 ) => %d\n",memcmp( "Hello World","Hello World",5 ) );    
36. printf("memcmp( "Hello\\0\\0\\0","Hello\\0 World",8 ) => %d\n",memcmp( "Hello\0\0\0","Hello\0 World",8 ));    
37. printf("memcmp( "Hello World","hello World",11 ) => %d\n",memcmp( "Hello World","hello World",11 ));    
38.  
39. return 0;    40.    }

Conclusion:

So, in this tutorial, we have seen how strings can be compared in various ways. As we have seen, the stringCompare() function returns -1 for unequal strings, but this can be modified so that it returns ASCII value of mismatched character. You can use it in your code, which is best suited for you.

]]>
Wireshark Network Forensic Analysis Tutorial https://linuxhint.com/wireshark_network_forensic_analysis_/ Tue, 01 Sep 2020 12:32:43 +0000 https://linuxhint.com/?p=66624 Wireshark is an open-source network monitoring tool. We can use Wireshark to capture the packet from the network and also analyze the already saved capture. Wireshark can be installed through the below commands in Ubuntu.[1] $ sudo apt-get update [This is for updating Ubuntu packages]

$ sudo apt-get install wireshark [This is for installing Wireshark]

The above command should start the Wireshark installation process. If the below screenshot window occurs, we have to press “Yes”.

Once the installation is completed, we can Wireshark version using the below command.

$ wireshark –version

So, installed Wireshark version is 2.6.6, but from official link [https://www.wireshark.org/download.html], we can see the latest version is more than 2.6.6.

To install the latest Wireshark version, follow the below commands.

$ sudo add-apt-repository ppa:wireshark-dev/stable
$ sudo apt-get update
$ sudo apt-get install Wireshark

Or

We can install manually from the below link if the above commands do not help. https://www.ubuntuupdates.org/pm/wireshark

Once Wireshark is installed, we can start Wireshark from the command line by typing

“$ sudo wireshark”

Or

by searching from Ubuntu GUI.

Note that we will try to use the latest Wireshark [3.0.1] for further discussion, and there will be very little differences between different versions of Wireshark. So, everything will not match exactly, but we can understand the differences easily.

We can also follow https://linuxhint.com/install_wireshark_ubuntu/ if we need step by step Wireshark installation help.

Introduction to the Wireshark:

  • graphical interfaces and Panels:

Once Wireshark is launched, we can select the interface where we want to capture, and Wireshark window looks like below

Once we choose the correct interface for capturing the whole Wireshark window looks like below.

There are three sections inside Wireshark

  • Packet List
  • Packet Details
  • Packet Bytes

Here is the screenshot for understanding

E:\fiverr\Work\mail74838\BOOK - Linux Forensics Tools & Techniques\pic\1.png

Packet List: This section displays all packets captured by Wireshark. We can see the protocol column for the type of packet.

Packet Details: Once we click on any packet from Packet List, packet details show supported networking layers for that selected packet.

Packet Bytes: Now, for the selected field of the selected packet, hex (default, It can be changed to binary also) value will be shown under the Packet Bytes section in Wireshark.

  • Important Menus and Options:

Here is the screenshot from Wireshark.

E:\fiverr\Work\mail74838\BOOK - Linux Forensics Tools & Techniques\pic\2.png

Now there are many options, and most of them are self-explanatory. We will learn about those while doing analysis on captures.

Here are some important options are shown using a screenshot.

E:\fiverr\Work\mail74838\BOOK - Linux Forensics Tools & Techniques\pic\3.png

E:\fiverr\Work\mail74838\BOOK - Linux Forensics Tools & Techniques\pic\4.png

E:\fiverr\Work\mail74838\BOOK - Linux Forensics Tools & Techniques\pic\5.png

E:\fiverr\Work\mail74838\BOOK - Linux Forensics Tools & Techniques\pic\6.png

TCP/IP Fundamentals:

Before going to do packet analysis, we should be aware basics of networking layers [https://linuxhint.com/osi_network_layer_analsysis_wireshark/].

In general, there are 7 layers for the OSI model and 4 Layer for the TCP/IP model shown in the below diagram.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\osi_model.png

But in Wireshark, we will see below layers for any packet.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\7.png

Each layer has its job to do. Let’s have one quick look at each layer’s job.

Physical Layer: This layer can transmit or receive raw binary bits over a physical medium like Ethernet cable.

Data Link Layer: This layer can transmit or receive a data frame between two connected nodes. This layer can be divided into 2 components, MAC and LLC. We can see the MAC address of the device in this layer. ARP works in the Data Link Layer.

Network Layer: This layer can transmit or receive a packet from one network to another network. We can see the IP address (IPv4/IPv6) in this layer.

Transport Layer: This layer can transmit or receive data from one device to another using a port number. TCP, UDP are transport layer protocols. We can see the port number is used in this layer.

Application Layer: This layer is closer to the user. Skype, Mail service, etc. are the example of application layer software. Below are some protocols which run in the application layer

HTTP, FTP, SNMP, Telnet, DNS etc.

We will understand more while analyzing the packet in Wireshark.

Live Capture of network traffic

Here are the steps to capture on a live network:

Step1:

We should know where [Which Interface] to capture packets. Let’s understand the scenario for a Linux laptop, which has an Ethernet NIC card and Wireless card.

:: Scenarios ::

  • Both are connected and have valid IP addresses.
  • Only Wi-Fi is connected, but Ethernet is not connected.
  • Only Ethernet is connected, but Wi-Fi is not connected.
  • No interface is connected to the network.
  • OR there are multiple Ethernet and Wi-Fi cards.

Step2:

Open terminal using Atrl+Alt+t and type ifconfig command. This command will show all up interface with IP address if any interface has. We need to see the interface name and remember. The below screenshot shows the scenario of “Only Wi-Fi is connected, but Ethernet is not connected.”

Here is the screenshot of command “ifconfig” which shows that only wlan0 interface has the IP address 192.168.1.102. That means wlan0 is connected to the network, but ethernet interface eth0 is not connected. This means we should capture on the wlan0 interface to get to see some packets.

Step3:

Launch Wireshark, and you will see the interfaces list on the home page of Wireshark.

Step4:

Now click on the required interface, and Wireshark will start capturing.

See the screenshot to understand live capture. Also, look for Wireshark’s indication for “live capture is in progress” at the bottom of Wireshark.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\live_cap.png

Color coding of traffic in Wireshark:

We may have noticed from previous screenshots that different types of packets have a different color. Default color coding is enabled, or there is one option to enable color-coding. Look at the screenshot below

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\coloe_enabled.png

Here is the screenshot when color coding is disabled.

Here is the setting for coloring rules at Wireshark

After clicking “Coloring Rules” below window will be opened.

Here we can customize the coloring rules for Wireshark packets for each protocol. But the default setting is quite good enough for capture analysis.

Saving Capture to a file

After stopping the live capture, here are the steps to save any capture.

Step1:

Stop the live capture by clicking below the marked button from screenshot or by using shortcut “Ctrl+E”.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\stop_cap.png

Step2:

Now to save file go to File->save or use shortcut “Ctrl+S”

Step3:

Enter the file name and click on Save.

Loading a Capture file

Step1:

To load any existing saved file, we have to go to File->Open or use the shortcut “Ctrl+O”.

Step2:

Then choose the required file from the system and click open.

What important details can be found in packets that can help with forensic analysis?

To answer questions first, we need to know what kind of network attack we are dealing with. As there are different kinds of network attack which uses different protocols so we can not say any fix Wireshark packet field to identify any issue. We are going to find this answer when we will discuss each networking attack in detail under “Network Attack”.

Creating Filters on traffic type:

There may be many protocols in a capture, so if we are looking for any specific protocol like TCP, UDP, ARP, etc., we need to type the protocol name as a filter.

Example: To show all TCP packets, the filter is “tcp”.

For UDP filter is “udp”

Note that: After typing the filter name, if the color is green, that means it’s a valid filter or else its invalid filter.

Valid Filter:

Invalid Filter:


Creating filters on address:

There are two types of addresses we can think of in case of networking.

1. IP address [Example: X = 192.168.1.6]

Requirement Filter
Packets where IP is X ip.addr == 192.168.1.6

Packets where source IP is X ip.src == 192.168.1.6
Packets where destination IP is X ip.dst == 192.168.1.6

We can see more filters for ip after following below step shown in the screenshot

2. MAC address [Example: Y = 00:1e:a6:56:14:c0]

This will be similar to previous table.

Requirement Filter
Packets where MAC is Y eth.addr == 00:1e:a6:56:14:c0
Packets where source MAC is Y eth.src == 00:1e:a6:56:14:c0
Packets where destination MAC is Y eth.dst == 00:1e:a6:56:14:c0

Like ip, we can also get more filters for eth. See the below screenshot.

Check the Wireshark website for all available filters. Here is the direct link

https://www.wireshark.org/docs/man-pages/wireshark-filter.html

You can also check these links

https://linuxhint.com/filter_by_port_wireshark/

https://linuxhint.com/filter_by_ip_wireshark/

Identify a large amount of traffic being used and what protocol it’s using:

We can take help from Wireshark inbuilt option and find out which protocol packets are more. This is required because when there are millions of packets inside a capture, and also size is huge, it will be difficult to scroll through every packet.

Step 1:

First of all, the total number of packets in the capture file is shown at right bottom side

See below screenshot

Step 2:

Now go to Statistics->Conversations

See below screenshot

Now the output screen will be like this

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\conversations.png

Step 3:

Now let’s say we want to find out who (IP address) exchanges maximum packets under UDP. So, go to UDP->Click on Packets so that the max packet is displayed on top.

Look at the screenshot.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\udp_max.png

We can get the source and destination IP address, which exchanges maximum UDP packets. Now the same steps can be used for other protocol TCP also.

Follow TCP Streams to see the full conversation

To see full TCP conversations, follow the below steps. This will be helpful when we want to see what happens for one particular TCP connection.

Here are the steps.

Step1:

Right-click on TCP packet in Wireshark like below screenshot

Step2:

Now go to Follow->TCP Stream

Step3:

Now one new window will be opened showing the conversations. Here is the screenshot

Here we can see HTTP header information and then the content

||--------Header--------||
POST /wireshark-labs/lab3-1-reply.htm HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Referer: http://gaia.cs.umass.edu/wireshark-labs/TCP-wireshark-file1.html
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: multipart/form-data; boundary=---------------------------7e2357215050a
Accept-Encoding: gzip, deflate
Host: gaia.cs.umass.edu
Content-Length: 152327
Connection: Keep-Alive
Cache-Control: no-cache
||-----Content-----||
ontent-Disposition: form-data; name="file"; filename="alice.txt"
Content-Type: text/plain
ALICE'S ADVENTURES IN WONDERLAND
Lewis Carroll
THE MILLENNIUM FULCRUM EDITION 3.0
CHAPTER I
Down the Rabbit-Hole
Alice was beginning to get very tired of sitting by her sister
on the bank, and of having nothing to do: once or twice she had
peeped into the book her sister was reading, but it had no
pictures or conversations in it, `and what is the use of a book,'
thought Alice `without pictures or conversation?'
…..Continue…………………………………………………………………………………

Now let’s go through some famous networking attacks through Wireshark, understand the pattern of different networking attacks.

Network Attacks:

Network attack is a process to gain access to other network systems and then steal data without knowledge of the victim or inject malicious code, which makes the victim’s system into a mess. In the end, the target is to steal data and make use of it with a different purpose.

There are many types of networking attacks, and here we are going to discuss some of the important networking attacks. We have chosen below attacks such a way that we can cover different types of patterns of attack.

A. Spoofing/ Poisoning Attack (Example: ARP spoofing, DHCP spoofing, etc.)

B. Port Scan Attack (Example: Ping sweep, TCP Half-open, TCP full connect scan, TCP null scan, etc.)

C. Brute force Attack (Example: FTP username and password, POP3 password cracking)

D. DDoS Attack (Example: HTTP flood, SYN flood, ACK flood, URG-FIN flood, RST-SYN-FIN flood, PSH flood, ACK-RST flood)

E. Malware Attacks (Example: ZLoader, Trojans, Spyware, Virus, Ransomware, Worms, Adware, Botnets, etc.)

A. ARP Spoofing:

What is ARP Spoofing?

ARP spoofing is also known as ARP poisoning as an attacker, makes the victim update ARP entry with attacker MAC address. It’s like adding poison to correct ARP entry. ARP spoofing is a networking attack that allows the attacker to divert the communication between network hosts. ARP spoofing is one of the methods for Man in the middle attack( MITM).

Diagram:

This is the expected communication between Host and Gateway

This is the expected communication between Host and Gateway when the network is under attack.

Steps of ARP Spoofing Attack:

Step1: The attacker chooses one network and starts sending broadcast ARP requests to the sequence of IP addresses.

E:\fiverr\Work\manraj21\2.png

Wireshark Filter: arp.opcode == 1

Step2: Attacker checks for any ARP reply.

E:\fiverr\Work\rax1237\2.png

Wireshark Filter: arp.opcode == 2

Step3: If an attacker gets any ARP reply, then the attacker sends the ICMP request to check the reachability to that host. Now the attacker has the MAC address of these hosts whoever sent ARP reply. Also, the host who has sent ARP reply updates its ARP cache with the attacker IP and MAC assuming that that is the real IP and MAC address.

Wireshark Filter: icmp

Now from the screenshot, we can say any data comes from 192.168.56.100 or 192.168.56.101 to IP 192.168.56.1 will reach to attacker MAC address, which is claiming as ip address 192.168.56.1.

Step4: After ARP spoofing, there may be multiple attacks like Session hijack, DDoS attack. ARP spoofing is just the entry.

So, you should look for these above patterns to get hints of the ARP spoofing attack.

How to avoid it?

  • ARP spoofing detection and prevention software.
  • Use HTTPS instead of HTTP
  • Static ARP entries
  • VPNS.
  • Packet filtering.

B. Identify Port Scan attacks with Wireshark:

What is Port scanning?

Port scanning is a type of networking attack where attackers start sending a packet to different port numbers to detect the status of the port if it’s open or closed or filtered by a firewall.

How to detect Port scanning in Wireshark?

Step1:

There are many ways to look into Wireshark captures. Suppose we observe that there are contentious multiple SYN or RST packet in captures. Wireshark Filter: tcp.flags.syn == 1 or tcp.flags.reset == 1

There is another way to detect it. Go to Statistics->Conversions->TCP [Check Packet Column].

Here we can see so many TCP communications with different ports [Look at Port B], but packet numbers are only 1/2/4.

Step2:

But there is no TCP connection observed. Then it’s a sign of port scan.

Step3:

From below capture, we can see SYN packets were sent to port numbers 443, 139, 53, 25, 21, 445, 23, 143, 22, 80. As some of the ports [139, 53, 25, 21, 445, 443, 23, 143] were closed so attacker [192.168.56.1] received RST+ACK. But the attacker received SYN+ACK from port 80 (packet number 3480) and 22 (packet number 3478). This means port 80 and 22 are opened. Bu attacker was not interested in TCP connection it sent RST to port 80 (packet number 3479) and 22 (packet number 3479)

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\port_scan.png

Note that: Attacker can go for TCP 3-way handshake (Shown below), but after that attacker terminates the TCP connection. This is called a TCP full connect scan. This is also one type of port scan mechanism instead of a TCP half-open scan like discussed above.

1. The attacker sends SYN.

2. The victim sends SYN+ACK.

3. Attacker sends ACK

How to avoid it?

You can use a good firewall and intrusion prevention system (IPS). The firewall helps to control ports about its visibility, and IPS can monitor if any port scan is in progress and block the port before anyone gets full access to the network.

C. Brute force Attack:

What is the Brute Force Attack?

Brute Force Attack is a networking attack where the attacker tries a different combination of credentials to break any website or system. This combination may be a user name and password or any information that allows you to enter to system or website. Let’s have one simple example; we often use a very common password like password or password123, etc., for common usernames like admin, user, etc. So if the attacker makes some combination of username and password, this type of system can be easily breakable. But this is one simple example; things can go for a complex scenario also.

Now, we will take one scenario for File Transfer Protocol (FTP) where username and password are used to login. So, the attacker can try multiple usernames and password combinations to get into the ftp system. Here is the simple diagram for FTP.

Diagram for Brute Force Attchl for FTP Server:

FTP Server

Multiple wrong login attempts to FTP Server

One successful login attempt to FTP server

From the diagram, we can see that attacker tried multiple combinations of FTP usernames and passwords and got success after sometime.

Analysis on Wireshark:

Here is the whole capture screenshot.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\ftp_incorrect.png

This is just starting of capture, and we just highlighted one error message from the FTP server. An error message is “Login or password incorrect”. Before the FTP connection, there is a TCP connection, which is expected, and we are not going to details on that.

To see if there is more than one login fail message, we can tale the help of Wireshark filer ftp.response.code==530which is the FTP response code for login failure. This code is highlighted in the previous screenshot. Here is the screenshot after using the filter.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\ftp_login.png

As we can see, there are a total of 3 failed login attempts to the FTP server. This indicates there was a Brute Force Attack on the FTP server. One more point to remember that attackers may use botnet, where we will see many different IP addresses. But here for our example, we see only one IP address 192.168.2.5.

Here are the points to remember to detect Brute Force Attack:

1. Login failure for one IP address.

2. Login failure for multiple IP addresses.

3. Login failure for an alphabetically sequential username or password.

Types of Brute Force Attack:

1. Basic brute force attack

2. Dictionary attack

3. Hybrid brute force attack

4. Rainbow table attack

Is the above scenario, we have observed the “Dictionary attack” for cracking the FTP server username and password?

Popular tools used for brute force attack:

1. Aircrack-ng

2. John, the ripper

3. Rainbow crack

4. Cain and Abel

How to avoid Brute Force Attack?

Here are some points for any website or ftp or any other network system to avoid this attack.

1. Increase password length.

2. Increase password complexity.

3. Add Captcha.

4. Use two-factor authentications.

5. Limit login attempts.

6. Lock any user if the user crosses the number of failed login attempts.

D. Identify DDOS attacks with Wireshark:

What is DDOS Attack?

A distributed denial-of-service (DDoS) attack is a process to block legitimate network devices to get the services from the server. There may be many types of DDoS attacks like HTTP flood (Application Layer), TCP SYN (Transport Layer) message flood, etc.

Example Diagram of HTTP Flood:

HTTP SERVER

Client Attacker IP
Client Attacker IP
Client Attacker IP
Legitimate Client sent HTTP GET Request
|
|
|
Client Attacker IP

From the above diagram, we can see the Server receives many HTTP requests, and the server gets busy in service of those HTTP requests. But when a legitimate client sends an HTTP request, the server is unavailable to reply to the client.

How to Identify HTTP DDoS attack in Wireshark:

If we open a capture file, there are many HTTP requests (GET/POST, etc.) from different TCP source port.

Used filter: http.request.method == “GET

Let’s see the captured screenshot to understand it better.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\http_flood.png

From the screenshot, we can see attacker ip is 10.0.0.2, and it has sent multiple HTTP requests using different TCP port numbers. Now server got busy sending HTTP reply for all those HTTP requests. This is the DDoS attack.

There are many types of DDoS attacks using different scenarios like SYN flood, ACK flood, URG-FIN flood, RST-SYN-FIN flood, PSH flood, ACK-RST flood, etc.

Here is the screenshot for the SYN flood to the server.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\syn_flood.png

Note that: The basic pattern of DDoS attack is there will be multiple packets from the same IP or different IP using different ports to the same destination IP with high frequency.

How to stop the DDoS attack:

1. Immediately report to the ISP or Hosting provider.

2. Use the Windows firewall and contact your host.

3. Use DDoS detection software or routing configurations.

E. Identify Malware attacks with Wireshark?

What is Malware?

Malware words came from Malicious Software. We can think of Malware as a piece of code or software that is designed to do some damage on systems. Trojans, Spyware, Viruses, ransomware are different types of malware.

There are many ways malware gets into the system. We will take one scenario and try to understand it from Wireshark capture.

Scenario:

Here in example capture, we have two windows systems with IP address as

10.6.12.157 and 10.6.12.203. These hosts are communicating with the internet. We can see some HTTP GET, POST, etc. operations. Let’s find out which windows system got infected, or both got infected.

Step1:

Let’s see some HTTP communication by these hosts.

After using the below the filter, we can see all HTTP GET request in the capture

“http.request.method == “GET””

Here is the screenshot to explain the content after the filter.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\http_get.png

Step2:

Now out of these, the suspicious one is GET request from 10.6.12.203, so we can follow TCP stream [see below screenshot] to find out the more clearly.

Here are the findings from following TCP stream

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\dll.png

Step3:

Now we can try exporting this june11.dll file from pcap. Follow the below screenshot steps

a.

b.

c. Now click on Save All and select destination folder.

d. Now we can upload june11.dll file to virustotal site and get the output as below

This confirms that june11.dll is a malware that got downloaded to the system [10.6.12.203].

Step4:

We can use the below filter to see all http packets.

Used Filter: “http”

Now, after this june11.dll got into the system we can see there is multiple POST from 10.6.12.203 system to snnmnkxdhflwgthqismb.com. The user did not do this POST, but the downloaded malware started doing this. It’s very difficult to catch this type of issue on run time. One more point to be noticed that the POST are simple HTTP packets instead of HTTPS, but most of the time, ZLoader packets are HTTPS. In that case, it’s quite impossible to see it, unlike HTTP.

This is HTTP post-infection traffic for ZLoader malware.

E:\fiverr\Work\Linuxhint_mail74838\BOOK - Linux Forensics Tools & Techniques\pic\post.png

Summary of malware analysis:

We can say 10.6.12.203 got infected because of downloading june11.dll but did not get any more information about 10.6.12.157 after this host downloaded invoice-86495.doc file.

This is an example of one type of malware, but there may be different types of malware which work in a different style. Each has a different pattern to damage systems.

Conclusion and next learning steps in Network Forensic Analysis:

In conclusion, we can say there many types of network attacks. It’s not an easy job to learn everything in detail for all attacks, but we can get the pattern for famous attacks discussed in this chapter.

In summary, here are the points we should know step by step to get the primary hints for any attack.

1. Know basic knowledge of the OSI/ TCP-IP layer and understand the role of each layer. There are multiple fields in each layer, and it carries some information. We should be aware of these.

2. Know the basics of Wireshark and get comfortable using it. Because there are some Wireshark options that help us to get the expected information easily.

3. Get an idea for attacks discussed here and try to match the pattern with your real Wireshark capture data.

Here are some tips for the next learning steps in Network Forensic Analysis:

1. Try to learn advanced features of Wireshark for a quick, large file, complex analysis. All documents about Wireshark are easily available in the Wireshark website. This gives you more strength to Wireshark.

2. Understand different scenarios for the same attack. Here is an article we have discussed port scan giving an example as TCP half, full connect scan, but there are many other types of port scans like ARP scan, Ping Sweep, Null scan, Xmas Scan, UDP scan, IP protocol scan.

3. Do more analysis for sample capture available on the Wireshark website instead of waiting for real capture and start the analysis. You can follow this link to download sample captures and try to do basic analysis.

4. There are other Linux open-source tools like tcpdump, snort which can be used to do the capture analysis along with Wireshark. But the different tool has a different style of doing analysis; we need to learn that first.

5. Try to use some open-source tool and simulate some network attack, then capture and do the analysis. This gives confidence, and also, we will be familiar with the attack environment.

]]>
How to use pipe function in C language https://linuxhint.com/using_pipe_function_c_language/ Fri, 31 Jul 2020 11:05:52 +0000 https://linuxhint.com/?p=64456

A pipe is a medium for communication between processes. One process writes data to the pipe, and another process reads the data from the pipe. In this article, we will see how the pipe() function is used to implement the concept using C language.

About Pipe

In the pipe, the data is maintained in a FIFO order, which means writing data to one end of the pipe sequentially and reading data from another end of the pipe in the same sequential order.

If any process reads from the pipe, but no other process has not written to the pipe yet, then read returns end-of-file. If a process wants to write to a pipe, but there is no other process attached to the pipe for reading, then this is an error condition, and the pipe generates a SIGPIPE signal.

Header File

#include <unistd.h>

Syntax

int pipe (int filedes[2])

Arguments

This function takes a single argument, an array of two integers (filedes). filedes[0] is used for reading from the pipe, and filedes[1] is used for writing to the pipe. The process which wants to read from the pipe should close filedes[1], and the process which wants to write to the pipe should close filedes[0].  If the unnecessary ends of the pipe are not explicitly closed, then end-of-file(EOF) will never be returned.

Return values

On success, the pipe() returns 0, for failure the function returns -1.

Pictorially, we can represent the pipe() function as follows:

Below are a few examples depicting how to use the pipe function in C language.

Example1

In this example, we will see how the pipe function works. Though using a pipe in a single process is not very useful, but we will get an idea.

// Example1.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int n;
    int filedes[2];
    char buffer[1025];
    char *message = "Hello, World!";

    pipe(filedes);
    write(filedes[1], message, strlen(message));

    if ((n = read ( filedes[0], buffer, 1024 ) ) >= 0) {
        buffer[n] = 0;  //terminate the string
        printf("read %d bytes from the pipe: "%s"\n", n, buffer);
    }  
    else
        perror("read");
    exit(0);
}

Here we have first created a pipe using pipe() function then written to the pipe using fildes[1] end. Then, the data has been read using the other end of the pipe, which is filedes[0]. For reading and writing to the file, we used to read() and write() functions.

Example2

In this example, we will see how parent and child processes communicate using the pipe.

// Example2.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main()
{
        int     filedes[2], nbytes;
        pid_t   childpid;
        char    string[] = "Hello, world!\n";
        char    readbuffer[80];

        pipe(filedes);
       
        if((childpid = fork()) == -1)
        {
                perror("fork");
                exit(1);
        }

        if(childpid == 0)
        {
                close(filedes[0]);//Child process does not need this end of the pipe

                /* Send "string" through the output side of pipe */
                write(filedes[1], string, (strlen(string)+1));
                exit(0);
        }
        else
        {
                /* Parent process closes up output side of pipe */
                close(filedes[1]);//Parent process does not need this end of the pipe

                /* Read in a string from the pipe */
                nbytes = read(filedes[0], readbuffer, sizeof(readbuffer));
                printf("Read string: %s", readbuffer);
        }
       
        return(0);
}

First, one pipe has been created using pipe function then a child process has been forked. Then, the child process closes the read end and writes to the pipe. The parent process closes the write end and reads from the pipe and displays it. Here data flow is only one way that is from child to parent.

Conclusion:

pipe() is a powerful system call in Linux. In this article, we have seen only one-way data flow, one process writes, and another process reads, creating two pipes we can achieve bi-directional data flow also.

]]>
How to use mmap function in C language? https://linuxhint.com/using_mmap_function_linux/ Sun, 26 Jul 2020 05:11:16 +0000 https://linuxhint.com/?p=63916 The mmap() function is used for mapping between a process address space and either files or devices. When a file is mapped to a process address space, the file can be accessed like an array in the program. This is one of the most efficient ways to access data in the file and provides a seamless coding interface that is natural for a data structure that can be assessed without he abstraction of reading and writing from files. In this article, we are going to discuss how to use the mmap() function in Linux. So, let’s get started.

Header File:

#include <sys/mman.h>

Syntax:

void * mmap (void *address, size_t length, int protect, int flags, int filedes,
off_t offset)

Arguments:

The function takes 6 arguments:

1. address:

This argument gives a preferred starting address for the mapping. If another mapping does not exist there, then the kernel will pick a nearby page boundary and create the mapping; otherwise, the kernel picks a new address. If this argument is NULL, then the kernel can place the mapping anywhere it sees fit.

2. length:

This is the number of bytes which to be mapped.

3. protect:

This argument is used to control what kind of access is permitted. This argument may be logical ‘OR’ of the following flags PROT_READ | PROT_WRITE | PROT_EXEC | PROT_NONE.  The access types of read, write and execute are the permissions on the content.

4. flags:

This argument is used to control the nature of the map. Following are some common values of the flags:

  • MAP_SHARED: This flag is used to share the mapping with all other processes, which are mapped to this object. Changes made to the mapping region will be written back to the file.
  • MAP_PRIVATE: When this flag is used, the mapping will not be seen by any other processes, and the changes made will not be written to the file.
  • MAP_ANONYMOUS / MAP_ANON: This flag is used to create an anonymous mapping. Anonymous mapping means the mapping is not connected to any files. This mapping is used as the basic primitive to extend the heap.
  • MAP_FIXED: When this flag is used, the system has to be forced to use the exact mapping address specified in the address If this is not possible, then the mapping will be failed.

5. filedes:

This is the file descriptor which has to be mapped.

6. offset:

This is offset from where the file mapping started. In simple terms, the mapping connects to (offset) to (offset+length-1) bytes for the file open on filedes descriptor.

Return values:

On success, the mmap() returns 0; for failure, the function returns MAP_FAILED.

Pictorially, we can represent the map function as follows:

For unmap the mapped region munmap() function is used :

Syntax:

int munmap(void *address, size_t length);

Return values:

On success, the munmap() returns 0; for failure, the function returns -1.

Examples:

Now we will see an example program for each of the following using mmap() system call:

  • Memory allocation (Example1.c)
  • Reading file (Example2.c)
  • Writing file (Example3.c)
  • Interprocess communication (Example4.c)

Example1.c

#include <stdio.h>
#include <sys/mman.h>

int main(){

    int N=5; // Number of elements for the array   
    int *ptr = mmap ( NULL, N*sizeof(int),
            PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANONYMOUS,
            0, 0 );
    if(ptr == MAP_FAILED){
        printf("Mapping Failed\n");
        return 1;
    }

    // Fill the elements of the array
    for(int i=0; i ");
    for(int i=0; i<N; i++){
        printf("
[%d] ",ptr[i]);
    }

    printf("
\n");
    int err = munmap(ptr, 10*sizeof(int));

    if(err != 0){
        printf("
UnMapping Failed\n");
        return 1;
    }
    return 0;
}

In Example1.c we allocate memory using mmap. Here we used PROT_READ | PROT_WRITE protection for reading and writing to the mapped region. We used the MAP_PRIVATE | MAP_ANONYMOUS flag. MAP_PRIVATE is used because the mapping region is not shared with other processes, and MAP_ANONYMOUS is used because here, we have not mapped any file. For the same reason, the file descriptor and the offset value is set to 0.

Example2.c

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[]){

    if(argc < 2){
        printf("File path not mentioned\n");
        exit(0);
    }
   
    const char *filepath = argv[1];
    int fd = open(filepath, O_RDONLY);
    if(fd < 0){
        printf("\n\"%s \" could not open\n",
               filepath);
        exit(1);
    }

    struct stat statbuf;
    int err = fstat(fd, &statbuf);
    if(err < 0){
        printf("\n\"%s \" could not open\n",
                       filepath);
        exit(2);
    }

    char *ptr = mmap(NULL,statbuf.st_size,
            PROT_READ|PROT_WRITE,MAP_SHARED,
            fd,0);
    if(ptr == MAP_FAILED){
        printf("Mapping Failed\n");
        return 1;
    }
    close(fd);

    ssize_t n = write(1,ptr,statbuf.st_size);
    if(n != statbuf.st_size){
        printf("Write failed");
    }

   

    err = munmap(ptr, statbuf.st_size);

    if(err != 0){
        printf("UnMapping Failed\n");
        return 1;
    }
    return 0;
}

In Example2.c we have mapped the file “file1.txt”. First, we have created the file, then mapped the file with the process. We open the file in O_RDONLY mode because here, we only want to read the file.

Example3.c

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[]){

    if(argc < 2){
        printf("File path not mentioned\n");
        exit(0);
    }
   
    const char *filepath = argv[1];
    int fd = open(filepath, O_RDWR);
    if(fd < 0){
        printf("\n\"%s \" could not open\n",
               filepath);
        exit(1);
    }

    struct stat statbuf;
    int err = fstat(fd, &statbuf);
    if(err < 0){
        printf("\n\"%s \" could not open\n",
                       filepath);
        exit(2);
    }

    char *ptr = mmap(NULL,statbuf.st_size,
            PROT_READ|PROT_WRITE,
                        MAP_SHARED,
            fd,0);
    if(ptr == MAP_FAILED){
        printf("Mapping Failed\n");
        return 1;
    }
    close(fd);

    ssize_t n = write(1,ptr,statbuf.st_size);
    if(n != statbuf.st_size){
        printf("Write failed\n");
    }


    // Reverse the file contents
    for(size_t i=0; i \n");
    n = write(1,ptr,statbuf.st_size);
    if(n != statbuf.st_size){
        printf("
Write failed\n");
    }

    err = munmap(ptr, statbuf.st_size);

    if(err != 0){
        printf("
UnMapping Failed\n");
        return 1;
    }
    return 0;
}

In Example3.c we have read and then write to the file.

Example4.c

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>

int main(){

    int N=5; // Number of elements for the array
   
    int *ptr = mmap(NULL,N*sizeof(int),
     PROT_READ | PROT_WRITE,
     MAP_SHARED | MAP_ANONYMOUS,
     0,0);    

    if(ptr == MAP_FAILED){
     printf("Mapping Failed\n");
     return 1;
    }

    for(int i=0; i < N; i++){
     ptr[i] = i + 1;
    }

    printf("Initial values of the array elements :\n");
    for (int i = 0; i < N; i++ ){
     printf(" %d", ptr[i] );
    }
    printf("\n");

    pid_t child_pid = fork();
   
    if ( child_pid == 0 ){
     //child
     for (int i = 0; i < N; i++){
         ptr[i] = ptr[i] * 10;
     }
    }
    else{
     //parent
     waitpid ( child_pid, NULL, 0);
     printf("\nParent:\n");

     printf("Updated values of the array elements :\n");
     for (int i = 0; i < N; i++ ){
         printf(" %d", ptr[i] );
     }
     printf("\n");
    }

    int err = munmap(ptr, N*sizeof(int));

    if(err != 0){
     printf("UnMapping Failed\n");
     return 1;
    }
    return 0;
}

In Example4.c first the array is initialized with some values, then the child process updates the values. The parent process reads the values updated by the child because the mapped memory is shared by both processes.

Conclusion:

The mmap() is a powerful system call. This function should not be used when there are portability issues because this function is only supported by the Linux environment. ]]> How to Use inotify API in C Language https://linuxhint.com/inotify_api_c_language/ Mon, 25 May 2020 01:50:37 +0000 https://linuxhint.com/?p=60449 Inotify is a Linux API used for file system events monitoring.

This article will show you how Inotify is used for tracking the creation, deletion, or modification of files and directories of the Linux file system.

To monitor a specific file or directory using Inotify, follow these steps:

  1. Create an inotify instance using the inotify_init()
  2. Add the full path of the directory or the file to monitor and the events to watch using the function inotify_add_watch(). In the same function, we specify which events (ON CREATE, ON ACCESS, ON MODIFY etc.), changes to the files, or changes to the directory must be monitored.
  3. Wait for events to occur and read the buffer, which contains one or more events that occurred, using the read() or select()
  4. Process the event which has occurred, then return to step 3 to wait for more events, and repeat.
  5. Remove the watch descriptor using the inotify_rm_watch()
  6. Close the inotify instance.

Now, we will see the functions that are used for Inotify API.

Header file: sys/inotify.h

inotify_init() function :

Syntax: int inotify_init (void)

Arguments: No arguments.

Return Values: On success, the function returns a new file descriptor, for failure the function returns -1.

inotify_add_watch() function:

Syntax: int inotify_add_watch ( int fd, const char *pathname, uint32_t mask )

Arguments:

This function takes three arguments.

The 1st argument (fd) is a file descriptor which refer to the inotify instance (return value of inotify_init() function) .

The 2nd argument is path of the directory or file which is being monitored.

The 3rd argument is a bitmask. The bitmask represents the events which are being watched. We can watch one or more events using bitwise-OR.

Return Values: On success, the function returns a watch descriptor, for failure the function returns -1.

inotify_rm_watch() function:

Syntax: int inotify_rm_watch ( int fd, int32_t wd )

Arguments:

This function takes two arguments.

The 1st argument (fd) is a file descriptor which refer to the inotify instance (return value of inotify_init() function) .

The 2nd argument (wd) is a watch descriptor (return value of inotify_add_watch()  function) .

Return Values:  On success, the function returns 0, for failure the function returns -1.

We use read() function(declared in unistd.h header file) to read the buffer, which is stored the information of the events occurred in the form of the inotify_event structure. The inotify_event structure is declared in sys/inotify.h header file:

struct inotify_event {
int32t   wd;
uint32_t  mask;
uint32_t  cookie;
uint32_t  len;
char name[];
}

The inotify_event structure represents a file system event returned by the inotify system and contains the following members:

  • wd: Watch descriptor (return value of inotify_add_watch() function)
  • mask: A bit mask that includes all the event types
  • cookie: Unique number that identifies events
  • len: Number of bytes in the name field
  • name: Name of the file or directory in which the event occurred

Below is a working example, using the Inotify API:

Inotify.c file:

#include<stdio.h>
#include<sys/inotify.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<fcntl.h> // library for fcntl function
 
#define MAX_EVENTS 1024  /* Maximum number of events to process*/
#define LEN_NAME 16  /* Assuming that the length of the filename
won't exceed 16 bytes*/
#define EVENT_SIZE  ( sizeof (struct inotify_event) ) /*size of one event*/
#define BUF_LEN     ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME ))
/*buffer to store the data of events*/
 
int fd,wd;
 
void sig_handler(int sig){
 
       /* Step 5. Remove the watch descriptor and close the inotify instance*/
       inotify_rm_watch( fd, wd );
       close( fd );
       exit( 0 );
 
}
 
 
int main(int argc, char **argv){
 
 
       char *path_to_be_watched;
       signal(SIGINT,sig_handler);
 
       path_to_be_watched = argv[1];
 
       /* Step 1. Initialize inotify */
       fd = inotify_init();
 
 
       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)  // error checking for fcntl
       exit(2);
 
       /* Step 2. Add Watch */
       wd = inotify_add_watch(fd,path_to_be_watched,IN_MODIFY | IN_CREATE | IN_DELETE);
 
       if(wd==-1){
               printf("Could not watch : %s\n",path_to_be_watched);
       }
       else{
              printf("Watching : %s\n",path_to_be_watched);
       }
 
 
       while(1){
 
              int i=0,length;
              char buffer[BUF_LEN];
 
              /* Step 3. Read buffer*/
              length = read(fd,buffer,BUF_LEN);
 
              /* Step 4. Process the events which has occurred */
              while(i<length){
 
                struct inotify_event *event = (struct inotify_event *) &buffer[i];
 
                  if(event->len){
                   if ( event->mask & IN_CREATE ) {
                   if ( event->mask & IN_ISDIR ) {
                     printf( "The directory %s was created.\n", event->name );
                     }
                     else {
                       printf( "The file %s was created.\n", event->name );
                    }
                    }
                    else if ( event->mask & IN_DELETE ) {
                    if ( event->mask & IN_ISDIR ) {
                      printf( "The directory %s was deleted.\n", event->name );
                    }
                    else {
                      printf( "The file %s was deleted.\n", event->name );
                    }
                    }
                    else if ( event->mask & IN_MODIFY ) {
                    if ( event->mask & IN_ISDIR ) {
                      printf( "The directory %s was modified.\n", event->name );
                    }
                    else {
                     printf( "The file %s was modified.\n", event->name );
                    }
                    }
                   }
                   i += EVENT_SIZE + event->len;
          }
    }
}

Output:

To execute the program and see the output, we must first open two terminals. One terminal is used to run the program Inotify.c. In the second terminal, we go to the path that is being watched by the Inotify.c. If we create any directory or file, modify any file, or delete any directory or file, we will see these on the first terminal.

In the Inotify.c example, the unistd.h header file is used for the read() and close() function, the stdlib.h header file is used for the exit() function, the signal.h header file is used for the signal() function and the SIG_INT macro (See signal handling for details), and the fcntl.h header file is used for the fcntl() function.

We declare fd (inotify instance) and wd (watch descriptor) as global variables so that these variables are accessible from all functions.

The fcntl() function is used so that when we read using the fd descriptor, the thread will not be blocked.

Next, we add a watch using the inotify_add_watch() function. Here, we pass fd, the path of the directory that will be watched, and the mask. You can pass the mask of the events you want to monitor using bitwise-OR.

Now, read the buffer. Information about one or more events is stored in the buffer. You can process all events one by one using the loop. You may check the event->mask to know which type of events have happened.

We use an infinite while loop to continuously check when events occurred. If no events have happened, the read() function returns with a  0. The return value of the read() function is stored in the length variable. When the value of the length variable is greater than zero, one or more events have occurred.

We use the SIG_INT signal (press Ctrl+C) to exit from the process. When you press Ctrl+C, the sig_handler() function is called (See signal handling for details). This function removes the watch descriptor, closes the inotify instance fd, and exits the program.

Conclusion

You can use Inotify API in your own applications for monitoring, debugging, automation, and more, in your own way. Here, we have seen the execution flow of Inotify API.

]]>
How to use gettimeofday function in C language? https://linuxhint.com/gettimeofday_c_language/ Mon, 04 May 2020 18:38:54 +0000 https://linuxhint.com/?p=59440 The gettimeofday() function gets the system’s clock time. The current time is expressed in elapsed seconds and microseconds since 00:00:00, January 1, 1970 (Unix Epoch). In this article, we are going to show you how to use the gettimeofday() function in Linux. So, let’s get started.

Syntax

int gettimeofday ( struct timeval *tp ,  struct timezone *tz )

The gettimeofday() function is defined in sys/time.h header file.

Arguments

This function takes two arguments:

The 1st argument points to the timeval structure. The timeval structure is declared as below in sys/time.h header file :

struct    timeval  {
  time_t        tv_sec ;   //used for seconds
  suseconds_t       tv_usec ;   //used for microseconds
}

The struct timeval structure represents a calendar time. It has two members:

  • tv_sec : It is the number of seconds since the epoch.
  • tv_usec :It is additional microseconds after number of seconds calculation since the epoch. .

The 2nd argument points to the timezone structure. It should normally be set to NULL because struct timezone is obsolete. This argument is for backwards compatibility only.

Return values

On success, the gettimeofday() return 0, for failure the function returns -1.

Simple Get Time and Print

#include <sys/time.h>
#include <stdio.h>

int main() {
  struct timeval current_time;
  gettimeofday(&current_time, NULL);
  printf("seconds : %ld\nmicro seconds : %ld",
    current_time.tv_sec, current_time.tv_usec);

  return 0;
}

Output:

Here, sys/time.h has been included for gettimeofday() function and timeval structure. The gettimeofday() function set the time in timeval (current_time) structure member. tv_sec is the integral number of seconds elapsed since the start of the UNIX epoch, on midnight UTC on January 1, 1970 and tv_usec is additional number of microseconds elapsed from tv_sec. If you run the program you should see the output. Each time you run the program the output will change.

NULL Argument Error

#include <sys/time.h>
#include <stdio.h>

int main() {
 
  struct timeval current_time;
  gettimeofday(NULL, NULL);
  return 0;
}

Output:

In this example shows that first argument of the gettimeofday() function should not be NULL. Compilation warning will come if the first argument is NULL.

Formatting Current Time Example

#include <time.h>
#include <sys/time.h>
#include <stdio.h>

int main() {
  struct timeval tv;
  time_t t;
  struct tm *info;
  char buffer[64];
 
  gettimeofday(&tv, NULL);
  t = tv.tv_sec;

  info = localtime(&t);
  printf("%s",asctime (info));
  strftime (buffer, sizeof buffer, "Today is %A, %B %d.\n", info);
  printf("%s",buffer);
  strftime (buffer, sizeof buffer, "The time is %I:%M %p.\n", info);
  printf("%s",buffer);

  return 0;
}

Output:

In this example shows how to print Date and Time in different format. It is not a very easy to represent dates from the return value of gettimeofday() function . Here, localtime() and strftime() functions are used to nicely represent the return value of gettimeofday().

 

The localtime() function takes an argument, which is a reference to a pointer of the tv_sec field of struct timeval and returns a reference to a pointer of a struct tm object.

 

The strftime() function will generate a personalized, formatted string showing the date and time from the struct tm pointer. Format specifiers are used for formatted display. For example, the format string “%d-%m-%Y %H:%M:%S” specifies the date and time in this form:

14-04-2020 13:09:42

Following are the conversion specifiers, may be used for formatted display:

Specifier Meaning
%a The abbreviated name of the weekday as per the present locale.
%A The name of the weekday as per the present locale.
%b Name of the abbreviated month as per the present locale.
%B Name of the full month as per present locale.
%c The preferred representation of date and time for the present locale.
%d As a decimal number for the month’s day (range 01 – 31).
%H Using 24-hrs (range 00 – 23) to the hour as decimal number.
%I Using 12-hrs (range 00 – 23) to the hour as decimal number.
%j As a decimal number for the day of the year (range 001-366).
%m As a decimal number for the month (range 01 – 12).
%M The decimal number of the minute.
%p Based on the specified time value, either ‘am’ or ‘pm’ or the equivalent strings for the current locale.
%S The decimal number of the second.
%x Preferred representation of the date for the current locale, but without time.
%X Preferred representation of the time for the current locale, but without date.
%y The year is decimal but no century (range from 00 – 99).
%Y The year is decimal including century.
%Z The time zone.

Using gettimeofday in order to Measure Program Execution Time

#include <sys/time.h>
#include <stdio.h>
 
int main() {
 
  struct timeval start, end;
  gettimeofday(&start, NULL);
 
  for (int i = 0; i <1e5 ; i++) {
  }
 
  gettimeofday(&end, NULL);
  printf("Time taken to count to 10^5 is : %ld micro seconds\n",
    ((end.tv_sec * 1000000 + end.tv_usec) -
    (start.tv_sec * 1000000 + start.tv_usec)));

  return 0;
}

Output:

This example shows that how gettimeofday() function may be used for calculation of execution time of a program.

Conclusion

In this way, the gettimeofday() function might be used in Linux. For porting existing code, the gettimeofday() function may be used but in new code it should not be used. clock_gettime()  function may be used instead of gettimeofday(). ]]> How to use signal handlers in C language? https://linuxhint.com/signal_handlers_c_programming_language/ Mon, 04 May 2020 18:29:51 +0000 https://linuxhint.com/?p=59457 In this article we are going to show you how to use signal handlers in Linux using C language. But first we will discuss what is signal, how it will generate some common signals which you can use in your program and then we will look how various signals can be handled by a program while the program executes. So, let’s start.

Signal

A signal is an event which is generated to notify a process or thread that some important situation has arrived. When a process or thread has received a signal, the process or thread will stop what its doing and take some action. Signal may be useful for inter-process communication.

Standard Signals

The signals are defined in the header file signal.h as a macro constant. Signal name has started with a “SIG” and followed by a short description of the signal. So, every signal has a unique numeric value. Your program should always use the name of the signals, not the signals number. The reason is signal number can differ according to system but meaning of names will be standard.

The macro NSIG is the total number of signal defined. The value of NSIG is one greater than the total number of signal defined (All signal numbers are allocated consecutively).

Following are the standard signals:

Signal Name Description
SIGHUP Hang-up the process. The SIGHUP signal is used to report disconnection of the user’s terminal, possibly because a remote connection is lost or hangs up.
SIGINT Interrupt the process. When the user types the INTR character (normally Ctrl + C) the SIGINT signal is sent.
SIGQUIT Quit the process. When the user types the QUIT character (normally Ctrl + \) the SIGQUIT signal is sent.
SIGILL Illegal instruction. When an attempt is made to execute garbage or privileged instruction, the SIGILL signal is generated. Also, SIGILL can be generated when the stack overflows, or when the system has trouble running a signal handler.
SIGTRAP Trace trap. A breakpoint instruction and other trap instruction will generate the SIGTRAP signal. The debugger uses this signal.
SIGABRT Abort. The SIGABRT  signal is generated when abort() function is called. This signal indicates an error that is detected by the program itself and reported by the abort() function call.
SIGFPE Floating-point exception. When a fatal arithmetic error occurred the SIGFPE signal is generated.
SIGUSR1 and SIGUSR2 The signals SIGUSR1 and SIGUSR2 may be used as you wish. It is useful to write a signal handler for them in the program that receives the signal for simple inter-process communication.

Default Action Of Signals

Each signal has a default action, one of the following:

Term: The process will terminate.
Core: The process will terminate and produce a core dump file.
Ign: The process will ignore the signal.
Stop: The process will stop.
Cont: The process will continue from being stopped.

Default action may be changed using handler function. Some signal’s default action cannot be changed. SIGKILL and SIGABRT signal’s default action cannot be changed or ignored.

Signal Handling

If a process receives a signal, the process has a choice of action for that kind of signal. The process can ignore the signal, can specify a handler function, or accept the default action for that kind of signal.

  • If the specified action for the signal is ignored, then the signal is discarded immediately.
  • The program can register a handler function using function such as signal or sigaction. This is called a handler catches the signal.
  • If the signal has not been neither handled nor ignored, its default action takes place.

We can handle the signal using signal or sigaction function. Here we see how the simplest signal() function is used for handling signals.

int signal () (int signum, void (*func)(int))

The signal() will call the func function if the process receives a signal signum. The signal() returns a pointer to function func if successful or it returns an error to errno and -1 otherwise.

The func pointer can have three values:

  1. SIG_DFL: It is a pointer to system default function SIG_DFL(), declared in h header file. It is used for taking default action of the signal.
  2. SIG_IGN: It is a pointer to system ignore function SIG_IGN(),declared in h header file.
  3. User defined handler function pointer: The user defined handler function type is void(*)(int), means return type is void and one argument of type int.

Basic Signal Handler Example

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_handler(int signum){

  //Return type of the handler function should be void
  printf("\nInside handler function\n");
}

int main(){
  signal(SIGINT,sig_handler); // Register signal handler
  for(int i=1;;i++){    //Infinite loop
    printf("%d : Inside main function\n",i);
    sleep(1);  // Delay for 1 second
  }
  return 0;
}

In the screenshot of the output of Example1.c, we can see that in main function infinite loop is executing. When user typed Ctrl+C, main function execution stop and the handler function of the signal is invoked. After completion of the handler function, main function execution resumed. When user type typed Ctrl+\, the process is quit.

Ignore Signals Example

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main(){
  signal(SIGINT,SIG_IGN); // Register signal handler for ignoring the signal

  for(int i=1;;i++){    //Infinite loop
    printf("%d : Inside main function\n",i);
    sleep(1);  // Delay for 1 second
  }
  return 0;
}

Here handler function is register to SIG_IGN() function for ignoring the signal action. So, when user typed Ctrl+C,  SIGINT signal is generating but the action is ignored.

Reregister Signal Handler Example

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

void sig_handler(int signum){
  printf("\nInside handler function\n");
  signal(SIGINT,SIG_DFL);   // Re Register signal handler for default action
}

int main(){
  signal(SIGINT,sig_handler); // Register signal handler
  for(int i=1;;i++){    //Infinite loop
    printf("%d : Inside main function\n",i);
    sleep(1);  // Delay for 1 second
  }
  return 0;
}

In the screenshot of the output of Example3.c, we can see that when user first time typed Ctrl+C, the handler function invoked. In the handler function, the signal handler re register to SIG_DFL for default action of the signal. When user typed Ctrl+C for second time, the process is terminated which is the default action of SIGINT signal.

Sending Signals:

A process also can explicitly send signals to itself or to another process. raise() and kill() function can be used for sending signals. Both functions are declared in signal.h header file.

int raise(int signum)

The raise() function used for sending signal signum to the calling process (itself). It returns zero if successful and a nonzero value if it fails.

int kill(pid_t pid, int signum)

The kill function used for send a signal signum to a process or process group specified by pid.

SIGUSR1 Signal Handler Example

#include<stdio.h>
#include<signal.h>

void sig_handler(int signum){
  printf("Inside handler function\n");
}

int main(){
  signal(SIGUSR1,sig_handler); // Register signal handler
  printf("Inside main function\n");
  raise(SIGUSR1);
  printf("Inside main function\n");
  return 0;
}

Here, the process send SIGUSR1 signal to itself using raise() function.

Raise with Kill Example Program

#include<stdio.h>
#include <unistd.h>
#include<signal.h>
void sig_handler(int signum){
  printf("Inside handler function\n");
}

int main(){
  pid_t pid;
  signal(SIGUSR1,sig_handler); // Register signal handler
  printf("Inside main function\n");
  pid=getpid();      //Process ID of itself
  kill(pid,SIGUSR1);        // Send SIGUSR1 to itself
  printf("Inside main function\n");
  return 0;
}

Here, the process send SIGUSR1 signal to itself using kill() function. getpid() is used to get the process ID of itself.

In the next example we will see how parent and child processes communicates (Inter Process Communication) using kill() and signal function.

Parent Child Communication with Signals

#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include<signal.h>
void sig_handler_parent(int signum){
  printf("Parent : Received a response signal from child \n");
}

void sig_handler_child(int signum){
  printf("Child : Received a signal from parent \n");
  sleep(1);
  kill(getppid(),SIGUSR1);
}

int main(){
  pid_t pid;
  if((pid=fork())<0){
    printf("Fork Failed\n");
    exit(1);
  }
  /* Child Process */
  else if(pid==0){
    signal(SIGUSR1,sig_handler_child); // Register signal handler
    printf("Child: waiting for signal\n");
    pause();
  }
  /* Parent Process */
  else{
    signal(SIGUSR1,sig_handler_parent); // Register signal handler
    sleep(1);
    printf("Parent: sending signal to Child\n");
    kill(pid,SIGUSR1);
    printf("Parent: waiting for response\n");
    pause();
  }
  return 0;
}

Here, fork() function creates child process and return zero to child process and child process ID to parent process. So, pid has been checked to decide parent and child process. In parent process, it is slept for 1 second so that child process can register signal handler function and wait for the signal from parent. After 1 second parent process send SIGUSR1 signal to child process and wait for the response signal from child. In child process, first it is waiting for signal from parent and when signal is received, handler function is invoked. From the handler function, the child process sends another SIGUSR1 signal to parent. Here getppid() function is used for getting parent process ID.

Conclusion

Signal in Linux is a big topic. In this article we have seen how to handle signal from the very basic, and also get a knowledge how the signal generate, how a process can send signal to itself and other process, how signal can be used for inter-process communication.

]]>