Collecting MAC and IP Adresses of Hosts Connected to Cisco Switches Using SNMP

The goal of this article is to introduce a script that automates a process of collecting MAC and IP address of hosts connected to Cisco switches using Simple Network Management Protocol (SNMP). We will configure SNMP version 2c and 3 on Cisco switches and create a BASH script that collects required data for us. For this purpose I have created a test network lab using GNS3. The topology consists of three Cisco virtual switch appliances running vIOS-L2 and one network management station (NMS) based on Kali Linux. Network hosts are simulated by Core Linux appliances connected to Cisco vIOS-l2 switches.

1. GNS3 Lab

1.1 List of software used for creating GNS3 lab

  • Host OS
    x86-64 Linux Fedora with installed GNS3 1.3.11 and Qemu1.4.0
  • Network Management Station
    Linux Kali 3.18.0-kali3-amd64
  • Swiches
    Cisco vIOS l2 Software (vios_l2-ADVENTERPRISEK9-M), Version 15.2
    Cisco Catalyst 3550 (C3550-IPSERVICESK9-M), Version 12.2(55)SE9
  • Network Host (End device)
    Linux Core 3.16.6-tinycore64

1.2 Network Topology Description

All virtual network and host devices are running inside GNS3 project and they are emulated by Qemu emulator and virtualizer. The only exception is a Cisco Catalyst 3550 switch that is connected to topology via GNS3 network cloud device. Using a hardware switch in the lab is a must as vIOS-L2 instances can only provide info about hosts connected to VLAN 1. It will be discussed later.

Picture1-Topology

Picture 1 - Network Topology

Switches have their SVI interfaces statically configured with IP address from subnet range 192.168.1.0/24. The hosts obtain  IP addresses automatically from DHCP server configured on switch vIOS-L2-1 (192.168.1.1).

The NMS station is occupied with two network interfaces. The first interface - Ethernet0 is connected to the subnet 192.168.1.0/24 and it has assigned an IP address 192.168.1.2/24. The second interface Ethernet1 is connected to a cloud device (L3 switch icon labeled with description c3550).

The cloud device is connected to the subnet 172.17.0.0/16 using NAT created by Qemu. The IP address of the Ethernet1 interface is 10.0.2.15/24 and it is obtained automatically from Qemu built-in DHCP server (subnet 10.0.2.0/24). Thanks to NAT connection the NMS station has connectivity to the network 172.17.0.0/16 where is a Cisco Catalyst 3550 switch located. The switch is statically configured with IP address 172.17.100.45/16.

2. SNMP Configuration on Switches and SNMPwalk

This part shows configuration of SNMP agents on Cisco switches and an example of using snmpwalk command that is used to query SNMP agents. The switches are configured with different SNMP versions in order to test syntax of snmpwalk command used by BASH script. The SNMP version 2c is configured on the switch with IP address 192.168.1.30 and a version 3 is configured on the rest switches.

The switches configured with SNMP version 3 contain different security levels configuration. For instance, the switch vIOS-L2-1 (192.168.1.1) is configured with a security level AuthPriv, while the switch vIOS-L2-2 (192.168.1.10) is configured with a level NoAuthNoPriv. The security level AuthNoPriv is configured on the switch vIOS-L2-3 (192.168.1.20).

Cisco Catalyst 3550 (172.17.100.45) contains SNMP version 3 configuration with a security level AuthPriv. It is an old hardware switch and I use it in a lab for collecting MAC and IP addresses of hosts connected to switchports that are assigned to VLANs different from VLAN 1.

As I have mentioned before, I was only successful with collecting MACs of host connected to switchports in VLAN 1 of virtual switches (running vIOS-L2 image). For this reason I had to connected Catalyst 3550 switch to GNS3 lab in order to  tell the script to collect data from other VLANs.

2.1 Cisco Switch vIOS-L2-1 (192.168.1.1) configured for SNMPv3 and Security Level AuthPriv

SNMP version 3 is configured on Cisco switch vIOS-L2-1 (192.168.1.1) and it allows a read access to the switch for NMS. The configured security level is AuthPriv (priv) which means that either MD5 or SHA hash protocol is used for authentication and either DES or AES symmetric encryption algorithm for encryption of SNMP messages. The AuthPriv security level is a recommended to configure because it offers both authentication and encryption of SNMP messages therefore it is is the most secure level. Below is shown configuration on Cisco switch.

vIOS-L2-I(config)# snmp-server group V3Group v3 priv read V3Read
vIOS-L2-I(config)# snmp-server user V3User V3Group v3 auth md5 your_Auth_Password priv aes 128 your_Enc_Password
vIOS-L2-I(config)# snmp-server view V3Read iso included
vIOS-L2-I(config)# snmp-server group V3Group v3 priv context vlan- match prefix

Below is the example of using snmpwalk command started on NMS station. The command collects the entries from ARP table from the switch (192.168.1.1).

$ snmpwalk -v3 -On -l authPriv -u V3User -a MD5 -A your_Auth_Password -x AES -X your_Enc_Password 192.168.1.1 1.3.6.1.2.1.4.22.1.2

If we want to query CAM (MAC) address table we have to specify particular VLAN for which we want to collect entries. For instance to query entries for VLAN 100, the command is following:

$ snmpwalk -v3 -On -n vlan-100 -l authPriv -u V3User -a MD5 -A your_Auth_Password -x AES -X your_Enc_Password 192.168.1.1 1.3.6.1.2.1.17.4.3.1.1

Note: Collecting data from switch CAM table using SNMP protocol is not as straightforward as collecting data from ARP table. Overall four SNMP GET requests must be sent from NMS to single SNMP agent to get info about MAC addresses of hosts and the switchports the hosts are connected to. Moreover these SNMP GET requests must be sent for each VLAN configured on switch. I wrote a script that parse output from SNMP requests sent to query  CAM and ARP tables and create an output file for each switch. The file contains info about particular MAC address of host, switchport and IP address.

2.2 Cisco Switch vIOS-L2-3 (192.168.1.20) configured for SNMPv3 and Security Level AuthNoPriv

SNMP configuration below provides a read access to the switch for NMS with configured security level AuthnoPriv (auth). This level offers only authentication of SNMP messages,  SNMP messages are not encrypted.

vIOS-L2-3(config)# snmp-server group V3Group v3 auth read V3Read
vIOS-L2-3(config)# snmp-server user V3User V3Group v3 auth md5 your_Auth_Password
vIOS-L2-3(config)# snmp-server view V3Read iso included
vIOS-L2-3(config)# snmp-server group V3Group v3 auth context vlan- match prefix

Snmpwalk command that queries ARP table on switch with IP address 192.168.1.20 is following:

$ snmpwalk -v3 -On -l auth -u V3User -a md5 -A your_Auth_Password 192.168.1.20 1.3.6.1.2.1.4.22.1.2

2.3 Cisco Switch vIOS-L2-2 (192.168.1.10) configured for SNMPv3 and Security Level NoAuthNoPriv

SNMP configuration below allows a read access to the switch for NMS. The configured security level AuthNoPriv (noauth) is the less secure as it does not provide authentication nor encryption
of SNMP messages.

vIOS-L2-2(config)# snmp-server group V3Group v3 noauth read V3Read
vIOS-L2-2(config)# snmp-server user V3User V3Group v3
vIOS-L2-2(config)# snmp-server view V3Read iso included
vIOS-L2-2(config)# snmp-server group V3Group v3 priv context vlan- match prefix

Snmpwalk command that queries ARP table on switch with IP address 192.168.1.10 is following:

$ snmpwalk -v3 -On -u V3User 192.168.1.10 1.3.6.1.2.1.4.22.1.2

2.4 Cisco Switch vIOS-L2-4 (192.168.1.30) configured for SNMP v2c

We want the script to support an old SNMP version 1 n 2c as it is still used by some network devices. Configuration below provides a read access to the switch vIOS-L2-4 (192.168.1.30) for NMS. It is not recommended to configure SNMP v2 as it does not provide authentication nor encryption of SNMP messages.

vIOS-L2-4(config)# snmp-server community public RO

Snmpwalk command that queries ARP table on switch with IP address 192.168.1.10 is following:

$ snmpwalk -v 2c -On -c public 192.168.1.30 1.3.6.1.2.1.4.22.1.2

In case we want to collect entries from CAM table we have to add character '@' to the community string together with VLAN ID. For instance, to query instances for VLAN 100, the snmpwalk command has the following syntax:

$ snmpwalk -v 2c -On -c public@100 192.168.1.1 1.3.6.1.2.1.17.4.3.1.1

3. BASH Script for Collecting MAC and IP addresses of Host Connected to Cisco Switches

First download a getmac.sh and assign execute permission to the script.

$ chmod +x getmac.sh

Below is shown the syntax of BASH the script. Arguments -d, -f and -n are obligatory.

Picture2-Script_Syntax

Picture 2 -Script Syntax

The argument -f determines a path to the file where IPv4 addresses and SNMP credentials of switches are stored. The structure of the file is shown below. Parameters must be separated by commas.

192.168.1.20,3,authNoPriv,1,V3User,sha,your_Auth_Password
192.168.1.10,3,noAuthNoPriv,1,V3User
192.168.1.1,3,authPriv,1,V3User,md5,your_Auth_Password,aes,your_Enc_Password
192.168.1.30,2c,public,1
172.17.100.45,2c,public,1
172.17.100.45,2c,public,100

Legend
Column Number - Parameter - Example
1 - IPv4 address of the switch - 192.168.1.20
2 - SNMP version - 1,2c, or 3
3 - Security level (v3) or the name of community string (v1, v2c) - noAuthNoPriv (v3), AuthNoPriv (v3), authPriv (v3) or public (v1, v2c)
4 - VLAN ID - (1-4094)
5 - Username (v3 only) - V3User
6 - Authentication protocol (v3 only) - md5 or sha
7 - Authentication password (v3 only) - your_Auth_Password
8 - Encryption algorithm (v3 only) - des or aes
9 - Encryption password (v3 only) - your_Enc_Password

Notice the last two lines in the file. To collect MAC and IP of hosts connected to switch with IP address 172.17.100.45 for VLAN1 and VLAN100, the file has to contain two lines, one for each VLAN.

The argument -d specifies a directory where the result will be stored. Create a directory with the command:

$ mkdir result

The argument -tells the script what is a maximum number of MACs (hosts) allowed on a single switchport. Normally we have only one host (MAC address) connected to a single switchport. Therefore we have to set n value to 1. But in case they are two or more hosts connected to a single switchport, we need to increase the 'n' value. For instance if we have a computer connected to a Cisco VOIP phone and the phone is connected to a switchport, they are two MAC addresses presented in CAM table for the switchport. In this case we have to set argument 'n' to 2.

The script uses argument -n to distinguish between a trunk port that connects switch to another switch and the switchports connecting end devices to the network. For instance if you enter value -n 1 and a switch founds two MAC addresses associated with a switchport then the port is considered to be a trunk port. Trunk ports and their associated MAC addresses are not added to the result files.

4. Script Testing

To make using BASH script easier for you I decided to create Vmware NMS appliance based on Linux Core and share it with you. The appliance is loaded with snmpwalk command and the script stored in /home/tc/ directory. All you need to do is following:

4.1 Assign IP address to NMS

$ sudo ip addr add 192.168.1.2/24 dev eth0
$ echo "ip addr add 192.168.1.2/24 dev eth0" >> /opt/bootlocal.sh

4.2 Create file containing IP addresses of the switches and SNMP credentials

$ vim iplist.txt
192.168.1.20,3,authNoPriv,1,V3User,sha,your_Auth_Password
192.168.1.10,3,noAuthNoPriv,1,V3User
192.168.1.1,3,authPriv,1,V3User,md5,your_Auth_Password,aes,your_Enc_Password
192.168.1.30,2c,public,1
172.17.100.45,1,authPriv,1,V3User,md5,your_Auth_Password,aes,your_Enc_Password
172.17.100.45,1,authPriv,100,V3User,md5,your_Auth_Password,aes,your_Enc_Password

4.3 Create directory where result will be stored

$ mkdir result

Note: If you want to keep a content of the directory /home/tc/ you have to issue the command below otherwise changes gone after reboot. This is requirement of  Core Linux.

$ /usr/bin/filetool.sh -b

4.4 Testing

Now you can start the script with the command below. You can check the output of the script output_log.

$ ./getmac.sh -d result -f iplist.txt -n 1

The result is stored in a directory result.

Picture3-Result

Picture 3 - Content of Directory Result

End.

19 thoughts on “Collecting MAC and IP Adresses of Hosts Connected to Cisco Switches Using SNMP

  1. Thanks for the script!

    VERY useful. For some strange reason it doesn't give me the IP's of the connected hosts, just the connected switches.

      1. Hi!

        I get all MAC addresses perfectly, that's wonderfull =) .
        I'm thinking if our cisco switches has some sort of rule, that' will not allow sending the IP in the related table.

        We have a lot of hosts, and our network topology looks like your example.

        I have tested the oid's using snmpwalk, and the only ip's I get in return are those of other switches, our trunk ports.

        1. Now I understand the point. The script collects MACs and their ports from CAM table. It also collects MAC and IP addresses from ARP table. Then it pairs MAC + IP + Port and stores the result. If there is not IP address in ARP table, switch stores only MAC + port. The ARP table is fulfilled only if the hosts somehow need to communicate with the switch itself. For instance you issue the ping command to some of the switch interfaces or you manage switch via SSH. There is not reason for switch to store IP address of the forwarded packets. The switch works on Layer2 - it forwards frames based on the destination MAC address. That's why ARP table only contain few IP address. Those are the IPs of the hosts that communicate with switch itself or in case a switch is L3 and works pretty much as a router.

  2. root@ubuntu:~/sw/MIB-Tables# more mib_port_string_192.168.1.247
    1 = STRING: "Gi0/0"
    root@ubuntu:~/sw/MIB-Tables# more mib_port_int_int_192.168.1.247
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.49 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.81 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.247 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.249 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.250 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.251 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.252 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.253 = INTEGER: 1
    .1.3.6.1.2.1.4.35.1.8.1.1.4.192.168.1.254 = INTEGER: 1
    root@ubuntu:~/sw/MIB-Tables# more mib_port_int_192.168.1.247
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.49 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.81 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.247 = INTEGER: 4
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.249 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.250 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.251 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.252 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.253 = INTEGER: 3
    .1.3.6.1.2.1.4.35.1.6.1.1.4.192.168.1.254 = INTEGER: 3
    root@ubuntu:~/sw/MIB-Tables# more mib_mac_192.168.1.247
    192.168.1.49 = Hex-STRING: 00 50 56 81 54 C2
    192.168.1.81 = Hex-STRING: E0 3F 49 13 30 09
    192.168.1.247 = Hex-STRING: 50 00 00 16 00 00
    192.168.1.249 = Hex-STRING: 50 00 00 0B 00 01
    192.168.1.250 = Hex-STRING: 50 00 00 0A 00 01
    192.168.1.251 = Hex-STRING: 50 00 00 01 00 07
    192.168.1.252 = Hex-STRING: 50 00 00 02 00 07
    192.168.1.253 = Hex-STRING: 50 00 00 14 80 64
    192.168.1.254 = Hex-STRING: A0 8E 78 14 A4 15

    ====

    results
    root@ubuntu:~/sw/result# more switch_192.168.1.247.csv
    ,00 50 56 81 54 C2,192.168.1.49
    ,E0 3F 49 13 30 09,192.168.1.81
    ,50 00 00 16 00 00,192.168.1.247
    ,50 00 00 0B 00 01,192.168.1.249
    ,50 00 00 0A 00 01,192.168.1.250
    ,50 00 00 01 00 07,192.168.1.251
    ,50 00 00 02 00 07,192.168.1.252
    ,50 00 00 14 80 64,192.168.1.253
    ,A0 8E 78 14 A4 15,192.168.1.254

    why iam not able to see my port information here ??

  3. With your Script iam not able to snampwalk

    #
    # ARP MIB - 1.3.6.1.2.1.4.22.1.2 -> IP and MAC address
    # .1.3.6.1.2.1.4.22.1.2.28.172.17.100.2 = Hex-STRING: 00 30 88 17 9D DC
    # MAc address '00 30 88 17 9D DC' has IP 172.17.100.2

    # MAC MIB - 1.3.6.1.2.1.17.4.3.1.1 -> Instance and its corresponding MAC address
    # .1.3.6.1.2.1.17.4.3.1.1.0.48.136.23.157.220 = Hex-STRING: 00 30 88 17 9D DC
    # 0.48.136.23.157 has MAC address 00 30 88 17 9D DC

    # Integer port MIB - 1.3.6.1.2.1.17.4.3.1.2 -> Instance and Integer value of port
    # .1.3.6.1.2.1.17.4.3.1.2.0.48.136.23.157.220 = INTEGER: 22
    # 0.48.136.23.157.220 has value 22

    # Inger to Integer Insance MIB - 1.3.6.1.2.1.17.1.4.1.2
    # .1.3.6.1.2.1.17.1.4.1.2.22 = INTEGER: 18
    # Instance 22 has integer value 18

    # String port MIB - 1.3.6.1.2.1.31.1.1.1.1 -> Integer valune and its corresponding string value of port
    # .1.3.6.1.2.1.31.1.1.1.1.18 = STRING: Fa0/22
    # Integer instance 18 is port Fa0/22

    # RESULT: MAC address '00 30 88 17 9D DC' is on port Fa0/22

    ###########################################################################################################

    snmpwalk -v $snmpver -On -c $string $ip 1.3.6.1.2.1.17.4.3.1.1 | sed -e 's/\.1\.3\.6\.1\.2\.1\.17\.4\.3\.1\.1\.//g' >> MIB-Tables/mib_mac_$ip-$sufix
    snmpwalk -v $snmpver -On -c $string $ip 1.3.6.1.2.1.17.4.3.1.2 | sed -e 's/\.1\.3\.6\.1\.2\.1\.17\.4\.3\.1\.2\.//g'>> MIB-Tables/mib_port_int_$ip-$sufix
    snmpwalk -v $snmpver -On -c $string $ip 1.3.6.1.2.1.17.1.4.1.2 | sed -e 's/\.1\.3\.6\.1\.2\.1\.17\.1\.4\.1\.2\.//g'>> MIB-Tables/mib_port_int_int_$ip-$sufix
    snmpwalk -v $snmpver -On -c $string $ip 1.3.6.1.2.1.31.1.1.1.1 | sed -e 's/\.1\.3\.6\.1\.2\.1\.31\.1\.1\.1\.1\.//g'> MIB-Tables/mib_port_string_$ip

    Here is my SNMP walk

    root@ubuntu:~/sw/result# snmpwalk -v 2c -c test 192.168.1.247 1.3.6.1.2.1.17.4.3.1.1
    iso.3.6.1.2.1.17.4.3.1.1 = No Such Instance currently exists at this OID
    root@ubuntu:~/sw/result# snmpwalk -v 2c -c test 192.168.1.247 1.3.6.1.2.1.17.4.3.1.2
    iso.3.6.1.2.1.17.4.3.1.2 = No Such Instance currently exists at this OID
    root@ubuntu:~/sw/result# snmpwalk -v 2c -c test 192.168.1.247 1.3.6.1.2.1.17.1.4.1.2
    iso.3.6.1.2.1.17.1.4.1.2 = No Such Instance currently exists at this OID
    root@ubuntu:~/sw/result# snmpwalk -v 2c -c test 192.168.1.247 1.3.6.1.2.1.31.1.1.1.1
    iso.3.6.1.2.1.31.1.1.1.1.1 = STRING: "Gi0/0"
    iso.3.6.1.2.1.31.1.1.1.1.2 = STRING: "Gi0/1"
    iso.3.6.1.2.1.31.1.1.1.1.3 = STRING: "Gi0/2"
    iso.3.6.1.2.1.31.1.1.1.1.4 = STRING: "Gi0/3"
    iso.3.6.1.2.1.31.1.1.1.1.5 = STRING: "Nu0"

    I am using v2 with simple to test.

    Can you please let me know what is wrong here ?

    1. I guess, your switch has no Bridge Mib 1.3.6.1.2.1.17. However the script is dependent on this MIB. What platform do you use? I tested the script with Catalyst 3550 and vIOS-L2 only. Do you have the same result when you use the VM I used in the lab (here)?

  4. I tried below mentioned images.
    Let me explain what is my target to create this lab.

    we have live many switches we need to have report weekdly, what port have what MAC and IP address connected.

    We have DHCP, VLAN (data and voice seperate)

    User (PC/ Phone)----Access switch port----uplink Aggrigation--DHCP

    INET#show version
    Cisco IOS Software, vios_l2 Software (vios_l2-ADVENTERPRISEK9-M), Version 15.2(HI_20170202)FLO_DSGS7, EARLY DEPLOYMENT DEVELOPMENT BUILD, synced to FLO_DSGS7_POSTCOLLAPSE_TEAM_TRACK_DSGS_PI5
    Technical Support: http://www.cisco.com/techsupport
    Copyright (c) 1986-2017 by Cisco Systems, Inc.
    Compiled Thu 02-Feb-17 06:12 by mmen

    So is this script i can use to get information what iam looking for ?

    Thank you for the help

    1. I've tested the script with Cisco vIOS-L2 15.2. The script is working ok but only with VLAN1.

      snmpwalk -v3 -On -l authPriv -u V3User -a MD5 -A your_Auth_Password -x AES -X your_Enc_Password 192.168.1.2 1.3.6.1.2.1.17.4.3.1.1
      .1.3.6.1.2.1.17.4.3.1.1.0.15.201.42.202.0 = Hex-STRING: 00 0F C9 2A CA 00
      .1.3.6.1.2.1.17.4.3.1.1.0.15.201.181.15.0 = Hex-STRING: 00 0F C9 B5 0F 00
      .1.3.6.1.2.1.17.4.3.1.1.0.15.201.220.88.0 = Hex-STRING: 00 0F C9 DC 58 00

      However the script cannot collect the MAC in another VLANs.
      snmpwalk -v3 -On -n vlan-50 -l authPriv -u V3User -a MD5 -A your_Auth_Password -x AES -X your_Enc_Password 192.168.1.2 1.3.6.1.2.1.17.4.3.1.1
      Timeout: No Response from 192.168.1.2

      The switch is configured for prefix matching but is does not support context.
      snmp-server group V3Group v3 priv context vlan- match prefix

      vIOS-II#show snmp context

      I also manually configured the VLAN-50 but the result is the same.
      snmp-server group V3Group v3 priv context vlan-50

      More here.

    1. SNMPv3 is not solution as I got those errors using SNMPv3 (not tested v2). I guess the best solution would be Python script that connects as read only user and get copy of MAC, ARP tables. Added to my TODO list :)

  5. thanks Radovan for the script, really useful!
    I changed just a few thing in the Check PID function
    because I have a lot of snmpwalk running on the same host and I have to distinguish the user running the script:

    chisono=`id -un`
    while [ "$(ps -fu $chisono | grep snmpwalk | grep -v grep )" ]; do

  6. Hy Radovan, what about combining your "MAC Adress Collecting" script with the portstatus check of Hendrik Nielson (https://libreplanet.org/wiki/User:Rakhun/Profile)? Nielsons script gives a php website as output containing Index, Desc, Int, Type, Speed, Status, Idle time and Available for evey port. I modded this script to display I Err, O Err, CRC Err, VLAN too. Currently I'm adding PoE Statistics too. So the MAC addresses would be a powerful improvement! Greetings David

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.