I recently discovered you can use SNMP to trigger a Cisco device to write its configuration to a remote TFTP server. Apparently this feature has existed in Cisco devices in one form or another for over a decade, but somehow I’d missed it completely. This seems a far better alternative to getting in a muddle with Expect-style scripts to telnet or SSH into the device. One or more Access Control Lists can also be utilised to restrict access.
First of all, let’s configure the IOS device which will need to be running at least IOS 12.0. The first thing to do is create an Access Control List which matches the IP address of the “management station” which will be issuing the SNMP commands and for simplicities sake is also the TFTP server:
router(config)#access-list 20 permit host 192.0.2.1
router(config)#access-list 20 deny any |
router(config)#access-list 20 permit host 192.0.2.1
router(config)#access-list 20 deny any
Next we define an SNMP view that restricts how much of the tree is writable, allowing write access to everything is both unnecessary and inadvisable:
router(config)#snmp-server view myview ccCopyTable included |
router(config)#snmp-server view myview ccCopyTable included
Now we create an SNMP group that ties the ACL and view together:
router(config)#snmp-server group mygroup v3 priv write myview access 20 |
router(config)#snmp-server group mygroup v3 priv write myview access 20
Note that I’ve specified SNMPv3 along with the authPriv security level, not all devices support that so adjust accordingly. I’ve also not specified a read view so it will use the default v1default
view which can read pretty much everything. Next create a new user as a member of this group:
router(config)#snmp-server user myuser mygroup v3 auth md5 authsecret priv des privsecret |
router(config)#snmp-server user myuser mygroup v3 auth md5 authsecret priv des privsecret
Finally, restrict which TFTP servers can be written to, triggered by SNMP. This stops someone from making your device write files to an arbitrary TFTP server somewhere:
router(config)#snmp-server tftp-server-list 20 |
router(config)#snmp-server tftp-server-list 20
That should be all of the configuration needed for the Cisco device.
Now on our “management station” which can be anything provided it has a recent version of Net-SNMP installed, (CentOS 5.x works fine), first make sure TFTP is installed and running. Normally the TFTP server cannot create new files so create an empty file ready:
# touch /tftpboot/router.conf |
# touch /tftpboot/router.conf
Now install the various MIB files we’ll need. You don’t need these but for the sake of readability it’s easier to use the symbolic names rather than raw OID strings. You’ll need to download the following MIB files:
- CISCO-CONFIG-COPY-MIB
- CISCO-SMI
- CISCO-ST-TC
Put them in a directory such as ~/mibs and then configure Net-SNMP with the following two environment variables:
# export MIBDIRS=+${HOME}/mibs
# export MIBS=+CISCO-CONFIG-COPY-MIB |
# export MIBDIRS=+${HOME}/mibs
# export MIBS=+CISCO-CONFIG-COPY-MIB
You should be able to test that everything is configured correctly:
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 ccCopyTable
CISCO-CONFIG-COPY-MIB::ccCopyTable: No entries |
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 ccCopyTable
CISCO-CONFIG-COPY-MIB::ccCopyTable: No entries
Now we need to create a row in this table describing the copy operation we’d like to perform. Without getting too heavy into how SNMP tables work, we basically need to use a unique index number to refer to the row. As we’ve already shown, the table is empty so pick any random number, umm, 23! Create a new row with the following column values:
# snmpset -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 \
> ccCopyProtocol.23 i tftp \
> ccCopySourceFileType.23 i runningConfig \
> ccCopyDestFileType.23 i networkFile \
> ccCopyServerAddress.23 a 192.0.2.1 \
> ccCopyFileName.23 s router.conf
CISCO-CONFIG-COPY-MIB::ccCopyProtocol.23 = INTEGER: tftp(1)
CISCO-CONFIG-COPY-MIB::ccCopySourceFileType.23 = INTEGER: runningConfig(4)
CISCO-CONFIG-COPY-MIB::ccCopyDestFileType.23 = INTEGER: networkFile(1)
CISCO-CONFIG-COPY-MIB::ccCopyServerAddress.23 = IpAddress: 192.0.2.1
CISCO-CONFIG-COPY-MIB::ccCopyFileName.23 = STRING: router.conf |
# snmpset -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 \
> ccCopyProtocol.23 i tftp \
> ccCopySourceFileType.23 i runningConfig \
> ccCopyDestFileType.23 i networkFile \
> ccCopyServerAddress.23 a 192.0.2.1 \
> ccCopyFileName.23 s router.conf
CISCO-CONFIG-COPY-MIB::ccCopyProtocol.23 = INTEGER: tftp(1)
CISCO-CONFIG-COPY-MIB::ccCopySourceFileType.23 = INTEGER: runningConfig(4)
CISCO-CONFIG-COPY-MIB::ccCopyDestFileType.23 = INTEGER: networkFile(1)
CISCO-CONFIG-COPY-MIB::ccCopyServerAddress.23 = IpAddress: 192.0.2.1
CISCO-CONFIG-COPY-MIB::ccCopyFileName.23 = STRING: router.conf
Now if you re-run the snmptable command (with some extra flagsoup to help readability) you’ll see there’s now a row:
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser -Cb -Ci -Cw 80 192.0.2.254 ccCopyTable
SNMP table: CISCO-CONFIG-COPY-MIB::ccCopyTable
index Protocol SourceFileType DestFileType ServerAddress FileName UserName
23 tftp runningConfig networkFile 192.0.2.1 router.conf ?
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 2
index UserPassword NotificationOnCompletion State TimeStarted TimeCompleted
23 ? false ? ? ?
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 3
index FailCause EntryRowStatus ServerAddressType ServerAddressRev1
23 ? ? ipv4 "192.0.2.1" |
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser -Cb -Ci -Cw 80 192.0.2.254 ccCopyTable
SNMP table: CISCO-CONFIG-COPY-MIB::ccCopyTable
index Protocol SourceFileType DestFileType ServerAddress FileName UserName
23 tftp runningConfig networkFile 192.0.2.1 router.conf ?
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 2
index UserPassword NotificationOnCompletion State TimeStarted TimeCompleted
23 ? false ? ? ?
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 3
index FailCause EntryRowStatus ServerAddressType ServerAddressRev1
23 ? ? ipv4 "192.0.2.1"
This won’t initiate the operation until we set one more column to activate the table row:
# snmpset -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 \
> ccCopyEntryRowStatus.23 i active
CISCO-CONFIG-COPY-MIB::ccCopyEntryRowStatus.23 = INTEGER: active(1) |
# snmpset -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 \
> ccCopyEntryRowStatus.23 i active
CISCO-CONFIG-COPY-MIB::ccCopyEntryRowStatus.23 = INTEGER: active(1)
Now check the table again:
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X authsecret -u myuser -Cb -Ci -Cw 80 192.0.2.254 ccCopyTable
SNMP table: CISCO-CONFIG-COPY-MIB::ccCopyTable
index Protocol SourceFileType DestFileType ServerAddress FileName UserName
23 tftp runningConfig networkFile 192.0.2.1 router.conf ?
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 2
index UserPassword NotificationOnCompletion State TimeStarted
23 ? false successful 5:0:20:49.92
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 3
index TimeCompleted FailCause EntryRowStatus ServerAddressType
23 5:0:20:51.39 ? active ipv4
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 4
index ServerAddressRev1
23 "192.0.2.1" |
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X authsecret -u myuser -Cb -Ci -Cw 80 192.0.2.254 ccCopyTable
SNMP table: CISCO-CONFIG-COPY-MIB::ccCopyTable
index Protocol SourceFileType DestFileType ServerAddress FileName UserName
23 tftp runningConfig networkFile 192.0.2.1 router.conf ?
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 2
index UserPassword NotificationOnCompletion State TimeStarted
23 ? false successful 5:0:20:49.92
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 3
index TimeCompleted FailCause EntryRowStatus ServerAddressType
23 5:0:20:51.39 ? active ipv4
SNMP table CISCO-CONFIG-COPY-MIB::ccCopyTable, part 4
index ServerAddressRev1
23 "192.0.2.1"
You can see the state column now reads successful so check the empty file you created under /tftpboot
, it should now have the contents of the current configuration for your device.
The row in the table will be automatically removed after a few minutes but you can also explicitly remove it:
# snmpset -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 \
> ccCopyEntryRowStatus.23 i destroy
CISCO-CONFIG-COPY-MIB::ccCopyEntryRowStatus.23 = INTEGER: destroy(6)
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 ccCopyTable
CISCO-CONFIG-COPY-MIB::ccCopyTable: No entries |
# snmpset -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 \
> ccCopyEntryRowStatus.23 i destroy
CISCO-CONFIG-COPY-MIB::ccCopyEntryRowStatus.23 = INTEGER: destroy(6)
# snmptable -v 3 -l authPriv -a MD5 -A authsecret -x DES -X privsecret -u myuser 192.0.2.254 ccCopyTable
CISCO-CONFIG-COPY-MIB::ccCopyTable: No entries
There’s still a fair bit of functionality that I’ve skipped over, you might be able to use something other than TFTP or generate an SNMP trap on completion. Experiment with changing the Access Control Lists and stopping the TFTP server to see how the table output changes.