目录

摘要
开发环境要求
Hook开发需求
Hook代码编写
Hook代码编译
Hook Kea配置
总结
参考文献
附录

摘要

简单Kea DHCP开发案例教程。通过本篇文章使读者能够对Hook开发有一个大致轮廓。主要侧重操作,对于概念的说明请查看官网。申明:本篇使用的是官方文档案例

开发环境要求

  1. Ubuntu
  2. gcc编译环境 apt install gcc
  3. vim编辑器
  4. Kea相关Hook开发库(安装Kea即可)

Hook开发需求

Kea DHCPv4用于分配IPv4地址给客户端(也会传给客户端其他信息,比如DNS服务器地址)。假设需要根据客户硬件地址和客户请求IPv4地址进行分类,且记录感兴趣的客户端硬件地址和已分配IP地址。

Hook代码编写

  • version - Hook代码被编译时Kea代码使用的版本
  • load - 当Hook被服务器加载时调用
  • unload - 当Hook被服务器卸载是调用

version函数

用于检查Hook是否兼容当前正在运行的Kea服务器。

源码

// version.cc#include <hooks/hooks.h>extern "C" {int version() {return (KEA_HOOKS_VERSION);}
}

load和unload函数

  1. load肯定被调用,unload不一定被调用,比如系统异常关闭。
  2. 这两个函数主要用于资源的分配和关闭。
  3. load函数可以注册自定义callout名字,比如如下代码:
int load(LibraryHandle& libhandle) {// Register the callouts on the hooks. We assume that a header file declares the "classify" and "write_data" functions.libhandle.registerCallout("pkt4_receive", classify);libhandle.registerCallout("pkt4_send", write_data);// Open the log fileinteresting.open("/tmp/interesting.log", std::fstream::out | std::fstream::app);return (interesting ? 0 : 1);
}

源码

  1. 将创建两个文件,分别为library_common.h和load_unload.cc,library_common.h用于文件处理器声明。load_unload.cc用于定义load和unload函数。
// library_common.h
#ifndef LIBRARY_COMMON_H
#define LIBRARY_COMMON_H
#include <fstream>
// 日志文件处理器声明
extern std::fstream interesting;
#endif // LIBRARY_COMMON_H
  1. 定义load和unload函数源文件。==interesting.open的文件必须保证文件夹是存在的==,否则加载会失败
// load_unload.cc
#include <hooks/hooks.h>
#include "library_common.h"using namespace isc::hooks;// 日志文件处理器定义
std::fstream interesting;extern "C" {int load(LibraryHandle&) {interesting.open("/tmp/interesting.log",std::fstream::out | std::fstream::app);return (interesting ? 0 : 1);}int unload() {if (interesting) {interesting.close();}return (0);}
}

Callout函数

这里的Callout是所有Hook point的统称。并不是真的叫callout这个名字。

callout签名

返回0表示成功,非0表示失败。

extern "C" {int callout(CalloutHandle& handle);
}

callout参数

CalloutHandle对象提供2个方法getArgument和setArgument,获取和设置参数。下面的举例如何使用

// 服务端代码片段,演示设置参数
int count = 10;
boost::shared_ptr<Pkt4> pktptr = ... // Set to appropriate value
// 假设handle对象已经创建
handle.setArgument("data_count", count);
handle.setArgument("inpacket", pktptr);
// 调用 callouts
...
// 获取修改的值
handle.getArgument("data_count", count);
handle.getArgument("inpacket", pktptr);

源码

// pkt4_receive.cc
#include <hooks/hooks.h>
#include <dhcp/pkt4.h>
#include "library_common.h"
#include <string>using namespace isc::dhcp;
using namespace isc::hooks;
using namespace std;extern "C" {
// 在pkt4_receive时调用该函数
int pkt4_receive(CalloutHandle& handle) {// A pointer to the packet is passed to the callout via a "boost" smart// pointer. The include file "pkt4.h" typedefs a pointer to the Pkt4// object as Pkt4Ptr.  Retrieve a pointer to the object.Pkt4Ptr query4_ptr;handle.getArgument("query4", query4_ptr);// Point to the hardware address.HWAddrPtr hwaddr_ptr = query4_ptr->getHWAddr();// The hardware address is held in a public member variable. We'll classify// it as interesting if the sum of all the bytes in it is divisible by 4.//  (This is a contrived example after all!)long sum = 0;for (int i = 0; i < hwaddr_ptr->hwaddr_.size(); ++i) {sum += hwaddr_ptr->hwaddr_[i];}// Classify it.if (sum % 4 == 0) {// Store the text form of the hardware address in the context to pass// to the next callout.string hwaddr = hwaddr_ptr->toText();handle.setContext("hwaddr", hwaddr);}return (0);
};
}
// pkt4_send.cc
#include <hooks/hooks.h>
#include <dhcp/pkt4.h>
#include "library_common.h"
#include <string>using namespace isc::dhcp;
using namespace isc::hooks;
using namespace std;extern "C" {
// 在pkt4_send hook的时候调用
int pkt4_send(CalloutHandle& handle) {// Obtain the hardware address of the "interesting" client.  We have to// use a try...catch block here because if the client was not interesting,// no information would be set and getArgument would thrown an exception.string hwaddr;try {handle.getContext("hwaddr", hwaddr);// getContext didn't throw so the client is interesting.  Get a pointer// to the reply.Pkt4Ptr response4_ptr;handle.getArgument("response4", response4_ptr);// Get the string form of the IP address.string ipaddr = response4_ptr->getYiaddr().toText();// Write the information to the log file.interesting << hwaddr << " " << ipaddr << "\n";// ... and to guard against a crash, we'll flush the output stream.flush(interesting);} catch (const NoSuchCalloutContext&) {// No such element in the per-request context with the name "hwaddr".// This means that the request was not an interesting, so do nothing// and dismiss the exception.}return (0);
}
}

Hook代码编译

根据上面的操作,完整的文件列表如下:

编译

g++ -I <install-dir>/include/kea -L <install-dir>/lib -fpic -shared -o example.so load_unload.cc pkt4_receive.cc pkt4_send.cc version.cc -lkea-dhcpsrv -lkea-dhcp++ -lkea-hooks -lkea-log -lkea-util -lkea-exceptions

上面编译成功后会在编译目录下,看到 example.so

指向kea安装时的目录,除非你安装时指定–prefix,否则默认为/usr/local

选项 解释
-I 指定额外的头文件搜索路径DIRECTORY。
-L 指定额外的函数库搜索路径DIRECTORY
-fpic 表明使用地址无关代码,PIC:Position Independent Code.
-shared 生成共享目标文件
-o 指定生成库的名字
-l 连接时搜索指定的函数库LIBRARY

Hook Kea配置

复制

复制Hook库到/usr/local/lib/hooks/下(根据你的喜好你可以放置在任意位置)

编辑

编辑vim /usr/local/etc/kea/kea-dhcp4.conf,在文件的Dhcp4节点下添加如下配置

"hooks-libraries": [{"library" : "/usr/local/lib/hooks/example.so"
}]

重启

重启后,运行测试工具,成功的话可以在/tmp/interesting.log目录如下输出:

总结

Kea如何测试测试,请查阅Karaf教程之Config Admin服务的使用。

参考文献

Hooks Developer’s Guide

Hooks Libraries

Linux共享对象之编译参数fPIC


附录

源码附件

Kea DHCP Hooks开发相关推荐

  1. 刚学习了linux的DHCP 配置.呵呵.自己上来总结下.

    先来看DHCP的工作原理. DHCP (Dynamic Host Configuration Protocol) 下面的部分是google找的.... ~~~~~~~~~~~~~~~~~~~~~~~~ ...

  2. [RHEL5企业级Linux服务攻略]--第3季 DHCP服务全攻略

    1 DHCP原理  1.1 DHCP概述 DHCP(Dynamic Host Configuration Protocal)就是动态主机配置协议哈,可以自动配置主机的IP地址.子网掩码.网关及DNS等 ...

  3. 当设计模式遇上 Hooks

    简介: 数据结构与设计模式能够指导我们在开发复杂系统中寻得一条清晰的道路,既然都说 Hooks 难以维护,那就尝试让「神」来拯救这混乱的局面.对于「设计模式是否有助于我们写出更优雅的 Hooks 」这 ...

  4. 【笔记-node】《Egg.js框架入门与实战》、《用 React+React Hook+Egg 造轮子 全栈开发旅游电商应用》

    20210226-20210227:<Egg.js框架入门与实战> 课程地址:https://www.imooc.com/learn/1185 第一章 课程导学 01-01 课程介绍 一. ...

  5. 整理下react.hooks

    React HOOKS 整理内容 来自B站eeerinzhang https://www.bilibili.com/video/BV1JE411f7kV?t=838 阮一峰博客hooks 开发流程(改 ...

  6. 低成本可复用前端框架——Linke

    业务背景 目前团队内的开发模式多是面向组件的,UI层和逻辑层均强耦合在一起,由于业务的差异性,往往很难完全复用. 闲鱼前端业务处在高速发展不断尝试的阶段,如何能更快更稳定地完成需求,更好的支撑业务发展 ...

  7. typescript vuex_Vue3+TypeScript完整项目上手教程

    作者:TinssonTai https://juejin.im/post/6875713523968802829 一个完整的Vue3+Ts项目,支持.vue和.tsx写法 项目地址:https://g ...

  8. 基于f2从零实现移动端可视化编辑器

    往期推荐 在线IDE开发入门之从零实现一个在线代码编辑器 基于React+Koa实现一个h5页面可视化编辑器-Dooring 深度剖析github star数15.1k的开源项目redux-thunk ...

  9. 人类高质量文章:阿里大佬的回顾

    点击上方关注 前端技术江湖,一起学习,天天进步 前言 从未写过年度总结,恰逢今年是变化较大的一年,所以需要有一个总结仪式.同时希望在未来的每一年都能有一次年度总结,看看当前走过的路,也回望以往的不足. ...

最新文章

  1. 亚马逊员工流动率150%,每8个月相当于“大换血”,网友:贝佐斯不知足
  2. 遍历python字典的几种方法
  3. 【Linux】36.ubuntu删除vscode的缓存,可清理出几十G空间
  4. 判断字符串是否以指定字符开头
  5. LightOJ 1269 Consecutive Sum (Trie树)
  6. 把第三方jar包放入本地仓库
  7. Spring Data JPA 从入门到精通~实际工作的应用场景
  8. Golang——文件创建和写入、OpenFile追加写入、Open读取文件、ReadBytes缓冲区读取、os.Args、flag
  9. 安全戴尔服务器销售,PowerEdge T340
  10. WPF(Windows Presentation Foundation)用户界面框架
  11. 纽约的雪--纽约公立小学的故事
  12. 项目经理感悟之风险管理
  13. 学习笔记-OS - Exploits
  14. 安卓系统车牌离线识别,优秀的车牌识别算法
  15. Day16_IO框架1(File类, IO流, 字节流字符流, IO异常, Properties)
  16. 黑客来势汹汹,受害者能以牙还牙“黑回去”吗
  17. 人工智能/数据科学比赛汇总 2019.9
  18. openwrt 软件安装依赖冲突
  19. 一元风暴时买的域名,拿出来晒晒
  20. 记一次线程池引发的BUG,差点被祭天

热门文章

  1. 计算机信息技术的论文参考文献,计算机信息计算机论文,关于初中计算机信息技术教学中存在相关参考文献资料-免费论文范文...
  2. 工程师将大脑信号直接转化为语音
  3. 两岸猿声啼不住,轻舟已过万重山(再见 MySQL 索引~)
  4. 思考“中医与DBA”
  5. 微信小程序原生开发集成IM服务出现无法找到模块“tim-wx-sdk”的声明文件问题解决
  6. FindWindowEx死循环的问题
  7. Robust image stitching with multiple registrations之浅见
  8. hadoop基础教程(二) MapReduce 单词统计
  9. 『华语电影』周星驰电影经典对白经典台词(转载)
  10. python 知识大全_Python基础知识汇总