keepalived vrrp可以使用ipsec协议进行路由器之间的认证. 密码的长度最长是8, 超过的长度自动截断, 也就是说只要前8位一致, 密码就能通过.
例如两台主机的实例密码验证配置如下 :
authentication {
auth_type PASS
auth_pass 1234567890
}
authentication {
auth_type PASS
auth_pass 1234567891
}
以上不会报密码错误. 因为前8位是一致的.
查看源码, 和密码长度有关的代码有几处 :
1. keepalived/include/vrrp.h
#define VRRP_AUTH_NONE 0 /* no authentification -- rfc2338.5.3.6 */
#define VRRP_AUTH_PASS 1 /* password authentification -- rfc2338.5.3.6 */
#define VRRP_AUTH_AH 2 /* AH(IPSec) authentification - rfc2338.5.3.6 */
密码长度为8
#define VRRP_AUTH_LEN 8
vrrp数据包的数据结构, 里面包含了认证类型和认证密码 :
/* parameters per virtual router -- rfc2338.6.1.2 */
typedef struct _vrrp_t {
....
/* Authentication data */
int auth_type; /* authentification type. VRRP_AUTH_* */
uint8_t auth_data[8]; /* authentification data */
...
} vrrp_t;
因为使用uint8_t[8]存储密码, 所以长度8位用掉8个字节, 这个协定刚好和vrrp协议一致 :
http://www.ietf.org/rfc/rfc2338.txt
5.1 VRRP Packet Format
This section defines the format of the VRRP packet and the relevant
fields in the IP header.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Type | Virtual Rtr ID| Priority | Count IP Addrs|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Auth Type | Adver Int | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address (1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| . |
| . |
| . |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address (n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication Data (1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication Data (2) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
未达8字节的部分填充bit 0, 所以如果我们把密码长度拉长的话, 无形中和这个协定就出现了冲突, 你的环境中可能没有问题, 换到其他使用vrrp标准协议的场景, 可能就有问题了. 需要注意.
2. vrrp数据包解析代码, 密码处理函数, 用到了vrrp数据结构中设置的长度 :
keepalived/vrrp/vrrp_parser.c
3. 密码长度校验
static void
vrrp_auth_pass_handler(vector_t *strvec)
{
vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
char *str = vector_slot(strvec, 1);
int max_size = sizeof (vrrp->auth_data);
int str_len = strlen(str);
if (str_len > max_size) {
str_len = max_size;
log_message(LOG_INFO,
"Truncating auth_pass to %d characters", max_size);
}
memset(vrrp->auth_data, 0, max_size);
memcpy(vrrp->auth_data, str, str_len);
}
3. 密码长度校验
keepalived/vrrp/vrrp.c
所以如果需要调整密码长度超过8 , 需要修改2处代码 :
/* check the authentication if it is a passwd */
if (hd->auth_type == VRRP_AUTH_PASS) {
char *pw = (char *) ip + ntohs(ip->tot_len)
- sizeof (vrrp->auth_data);
if (memcmp(pw, vrrp->auth_data, sizeof(vrrp->auth_data)) != 0) {
log_message(LOG_INFO, "receive an invalid passwd!");
return VRRP_PACKET_KO;
}
}
所以如果需要调整密码长度超过8 , 需要修改2处代码 :
例如长度修改为16
1. keepalived/include/vrrp.h
重新编译即可, 注意场景中所有的keepalived都需要重新编译.
#define VRRP_AUTH_LEN 16 // 修改1
/* parameters per virtual router -- rfc2338.6.1.2 */
typedef struct _vrrp_t {
....
/* Authentication data */
int auth_type; /* authentification type. VRRP_AUTH_* */
uint8_t auth_data[16]; /* authentification data */ // 修改2
...
} vrrp_t;
重新编译即可, 注意场景中所有的keepalived都需要重新编译.
gmake && gmake install
现在可以设置最长16位的密码了.
例如两台主机的实例密码验证配置如下 :
[参考]
authentication {
auth_type PASS
auth_pass 1234567890
}
authentication {
auth_type PASS
auth_pass 1234567891
}
现在的话会报密码错误了, 需要改成一样的密码才行, 因为变成16位截断了.
2. keepalived/include/vrrp.h