为Twemproxy 添加 Auth
Twemproxy不支持Auth 指令。
struct conf_pool {
...
struct string password;
...
}
2.2 为password配置声明解析方法
char *conf_set_password(struct conf *cf,struct command *cmd,void *conf);
3.nc_server.h
3.1 为server_pool添加成员password
struct server_pool {
...
char password[128];
...
}
{ string("password"),
conf_set_password,
offsetof(struct conf_pool, password) },
static rstatus_t
conf_pool_init(struct conf_pool *cp, struct string *name)
{
...
cp->password.data = CONF_UNSET_PTR;
...
}
static void
conf_pool_deinit(struct conf_pool *cp)
{
...
...
}
string_deinit(&cp->password);
4.3 实现对password 配置的解析
char *
conf_set_password(struct conf *cf,struct command *cmd,void *conf)
{
uint8_t *p;
struct string *field, *value;
p = conf;
field = (struct string *)(p + cmd->offset);
if (field->data != CONF_UNSET_PTR) {
return "is a duplicate";
}
value = array_top(&cf->arg);
if (value->len == 0 ) {
return "password is null";
}
if (value->len >100 ) {
return "password is too long";
}
field->data = (char*)malloc(128);
memcpy(field->data,value->data,value->len);
field->data[value->len] = '\0';
field->len = value->len;
printf("password is:%s\n",field->data);
return CONF_OK;
}
4.4 将conf_pool中的password copy到server_pool中去
rstatus_t
conf_pool_each_transform(void *elem, void *data)
{
...
...
}
如此这番之后我们就为Twemproxy添加了配置密码的功能
下面我们实现两种Auth指令需求
if(cp->password.data != CONF_UNSET_PTR)
{
strcpy(sp->password,cp->password.data);
}else
{
sp->password[0] == '\0';//password 长度为0表示没有密码
}
Client to Twemproxy:
1.为Twemproxy添加Auth指令支持
1.1 nc_message.h
1.1.1 在MSG_TYPE_CODEC中添加AUTH ACTION的声明
#define MSG_TYPE_CODEC(ACTION)
...
ACTION( REQ_REDIS_AUTH ) /* 设置密码*/\
...
1.2 nc_redis.c
1.2.1 在没有arg(不包含hash key与action key)的指令中注册
static bool
redis_arg0(struct msg *r)
{
switch (r->type) {
...
case MSG_REQ_REDIS_AUTH:
...
}
return false;
}
1.2.2 在request解析中添加action auth的解析
void
redis_parse_req(struct msg *r)
{
...
for (p = r->pos; p < b->last; p++) {
ch = *p;
switch (state) {
...
case SW_REQ_TYPE:
...
switch (p - m) {
...
case 4:
...
if (str4icmp(m, 'a', 'u', 't', 'h'))
{//将auth的解析放在最后,因为auth指令总不是常用的
r->type = MSG_REQ_REDIS_AUTH;
break;
}
break;
...
default:
break;
}
...
break;
...
case SW_SENTINEL:
default:
NOT_REACHED();
break;
}
}
...
}
2. 为conn添加password设置是否成功的标记
2.1 nc_connection.h
2.1.1 为conn添加password设置成功与否的标记变量
struct conn {
...
unsigned setpassword:1; /* 标记是否设置了密码 */
...
}
2.2 nc_connection.c
2.2.2 初始化conn的setpassword成员
struct conn *
conn_get(void *owner, bool client, bool redis)
{
...
conn->setpassword = 0;
...
}
3. Auth功能实现
3.1 nc_request.c
3.1.1 过滤掉没有Auth的conn的请求,验证Auth
static bool
req_filter(struct context *ctx, struct conn *conn, struct msg *msg)
if(msg->type == MSG_REQ_REDIS_AUTH)
{//验证密码
struct server_pool *pool = conn->owner;
struct mbuf* p_buf = STAILQ_FIRST(&msg->mhdr);
char* p_start =p_buf->pos;
char* p_end = p_buf->last;
char passwordinfo[256];
sprintf(passwordinfo,
"*2\r\n$4\r\nauth\r\n$%d\r\n%s\r\n",
strlen(pool->password),
pool->password);
if(msg->mlen != strlen(passwordinfo)
|| p_end - p_start != msg->mlen//如果密码被分段了也认定为错误
|| memcmp(p_start+13,passwordinfo+13,msg->mlen-13)!=0)
{//密码错误
struct msg* pong = fGetAuthErrMsg();
conn->setpassword = 0;
fReturnMsgToClient(ctx,conn,pong,msg);
return true;
}else
{
conn->setpassword = 1;
struct msg* ok = fGetOKMsg();
fReturnMsgToClient(ctx,conn,ok,msg);
return true;
}
}
if(conn->setpassword == 0)
{//没有密码检测下是否需要密码
struct server_pool *pool = conn->owner;
if(pool->password[0]!=0)
{//表示需要密码
struct msg* pong = fGetNeedAuthMsg();
fReturnMsgToClient(ctx,conn,pong,msg);
return true;
}
}
struct msg* fGetNeedAuthMsg();
struct msg* fGetAuthErrMsg();
struct msg* fGetOKMsg();
3.3 nc_message.c
3.3.1 实现ACTION Auth 使用到的静态响应包
struct msg* fGetAuthErrMsg()
{
struct msg* pong = _msg_get();
struct mbuf *mbuf;
if(pong == NULL)
{
return NULL;
}
pong->mlen = 0;
mbuf = mbuf_get();
if (mbuf == NULL) {
msg_put(pong);
return NULL;
}
mbuf_insert(&(pong->mhdr), mbuf);
pong->p_key_info = NULL;
static int noauthlen = strlen("-ERR invalid password\r\n");
memcpy(mbuf->last,
"-ERR invalid password\r\n",
noauthlen);
mbuf->last += noauthlen;
pong->mlen += noauthlen;
return pong;
}
struct msg* fGetNeedAuthMsg()
{
struct msg* pong = _msg_get();
struct mbuf *mbuf;
if(pong == NULL)
{
return NULL;
}
pong->mlen = 0;
mbuf = mbuf_get();
if (mbuf == NULL) {
msg_put(pong);
return NULL;
}
mbuf_insert(&(pong->mhdr), mbuf);
pong->p_key_info = NULL;
static int noauthlen = strlen("-NOAUTH Authentication required.\r\n");
memcpy(mbuf->last,
"-NOAUTH Authentication required.\r\n",
noauthlen);
mbuf->last += noauthlen;
pong->mlen += noauthlen;
return pong;
}
struct msg* fGetOKMsg()
{
struct msg* OK = _msg_get();
struct mbuf *mbuf;
if(OK == NULL)
{
return NULL;
}
OK->mlen = 0;
mbuf = mbuf_get();
if (mbuf == NULL) {
msg_put(OK);
return NULL;
}
mbuf_insert(&(OK->mhdr), mbuf);
OK->p_key_info = NULL;
memcpy(mbuf->last,
"+OK\r\n",
5);
mbuf->last += 5;
OK->mlen += 5;
return OK;
}
Twemproxy To Redis:
1. 初始化conn,
1.1 nc_server.c
1.1.1 每当conn需要重连的时候都需要重置一下
rstatus_t
server_connect(struct context *ctx, struct server *server, struct conn *conn)
{
rstatus_t status;
ASSERT(!conn->client && !conn->proxy);
if (conn->sd > 0) {
/* already connected on server connection */
return NC_OK;
}
conn->setpassword = 0;//标记为没有设置密码
...
}
2. 发送Auth指令
2.1 nc_request.c
2.2.1 每当conn发送一个message但是又没有标记Auth的时候发送Auth指令
void
req_server_enqueue_imsgq(struct context *ctx,
struct conn *conn,
struct msg *msg)
{
ASSERT(msg->request);
ASSERT(!conn->client && !conn->proxy);
struct server *ser = (struct server *)conn->owner;
if(ser->owner->password[0]!=0 && conn->setpassword==0)
{//要设置密码,但是还没有设置成功
struct msg* p_password = fGetAuthMsg(ser->owner->password);
conn->setpassword = 1;//只管发送第一个请求前发送一次auth指令,其他的就不管了
req_server_enqueue_imsgq(ctx,conn,p_password);
}
//广播命令只有在最后一次发送时,加入timeout中
if ((!msg->noreply)
&&(!msg->broadcast
||msg->ui32_broadcast_number==0
)) {
msg_tmo_insert(msg, conn);
}
TAILQ_INSERT_TAIL(&conn->imsg_q, msg, s_tqe);
stats_server_incr(ctx, conn->owner, in_queue);
stats_server_incr_by(ctx, conn->owner, in_queue_bytes, msg->mlen);
}
2.3 nc_message.h
2.3.1 声明AuthMsg
struct msg* fGetAuthMsg(char* password);
2.4 nc_message.c
2.4.1 实现AuthMsg
struct msg* fGetAuthMsg(char* password)
{
struct msg* AuthPassword = _msg_get();
struct mbuf *mbuf;
if(AuthPassword == NULL)
{
return NULL;
}
AuthPassword->mlen = 0;
mbuf = mbuf_get();
if (mbuf == NULL) {
msg_put(AuthPassword);
return NULL;
}
mbuf_insert(&(AuthPassword->mhdr), mbuf);
AuthPassword->p_key_info = NULL;
sprintf(mbuf->last,"*2\r\n$4\r\nauth\r\n$%d\r\n%s\r\n",strlen(password),password);
mbuf->last += strlen(mbuf->last);
AuthPassword->mlen += strlen(mbuf->last);
AuthPassword->swallow = 1;
return AuthPassword;
}
到此为Twemproxy添加Auth功能就已经实现了
后记:
当然这里面还是有很多地方并不完善,比如Twemproxy to Reid 的Auth 并没有管失败的情况。
没有将各个Redis节点之间的Auth分开,也没有与Client to Twemproxy分离。
至于这些就根据实际需求实现吧。
为Twemproxy 添加 Auth相关推荐
- Redis集群~StackExchange.Redis(10月6号版1.1.608.0)连接Twemproxy支持Auth指令了
对于StackExchange.Redis这个驱动来说,之前的版本在使用Proxy为Twemproxy代理时,它是不支持Password属性的,即不支持原始的Auth指令,而我也修改过源代码,为Com ...
- mongodb 安装和配置auth验证
为什么80%的码农都做不了架构师?>>> 安装 brew install mongodb mongodb 配置 启动 brew services start mongodb 创 ...
- Asterisk在mysql数据库中添加sip账号
Asterisk版本:15.5.0 系统版本:Ubuntu 14.04 添加sip账号有好几种方法,本文中描述的只是其中的一种方法.在网上我也找了好多配置sippeers账号的,始终没有配置成功,最后 ...
- laravel auth.php,Laravel 用户认证 Auth
很多应用是需要登陆后才能操作,Laravel提供了一个auth工具来实现用户的认证功能.并且有一个config/auth.php来配置auth工具.大概看一下auth工具的常用方法 Auth::che ...
- python后端需要什么基础_一个六年经验的python后端是怎么学习用java写API的(6) 基本的Auth...
描述 实现了依赖注入之后就可以方便的实现各种API的业务逻辑了,下一部的问题就在于权限,我们知道大部分的系统API并不是开放的,需要基本的用户体系(注册.登录.购买.会员.不同的role等等),例如管 ...
- mongo报错:not authorized on bb to execute command { create: \“xxx\“...}
mongo报错: {"ok" : 0,"errmsg" : "not authorized on bb to execute command { cr ...
- Python:Resquest模块
Requests: 让 HTTP 服务人类 虽然Python的标准库中 urllib2 模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 & ...
- CentOS7.4 安装mongodb
温馨提示:我的环境是腾讯云自带的CentOS7.4 x64 镜像,本地环境是win10 x64 专业版,ssh工具是用的win10 自带的cmd, 远程工具版本是Robo 3T 1.2.1 . 如果环 ...
- docker使用mongo_如何使用Docker在AWS上部署Mongo:初学者的权威指南
docker使用mongo 为什么需要这个? (Why you need this?) 因为JS + Python + Mongo =完整的数据开发 (Because JS + Python + Mo ...
最新文章
- 如何高效获取无线充电电能-无线节能组
- FPGA中建立时间和保持时间不满足如何解决
- 基于X-Engine引擎的实时历史数据库解决方案揭秘
- TPC-C中跑赢Oracle的OceanBase,最近有何惊艳?
- html页面判断其他div为空,将外部html加载到div - 页面加载然后变为空白
- 调用k8s api遇到CERTIFICATE_VERIFY_FAILED的问题解决方法
- numpy常用的一种高效切片方式
- setImageResource导致的ANR
- 计算机附件常用工具,Windows附件常用工具
- 通过iis发布网站、并添加ssl证书
- iOS - 毛玻璃效果
- Emitter使用方法
- 联想笔记本修复计算机还原系统失败,联想电脑重置电脑失败怎么办
- daytime协议的服务器和客户端程序,用socket套接字实现daytime协议服务器和客户端程序.doc...
- 游戏陪玩App,如雨后春笋般冒出,直接导致整个游戏陪玩源码市场的持续火爆
- 2020起重机司机(限桥式起重机)作业考试题库及起重机司机(限桥式起重机)实操考试视频
- Java 将Word保存为WPS和WPT格式
- 编程修养 值得看一下,先mark一下,回头看
- 【嵌入式物联网】NodeMCU开发板引脚介绍和主要技术参数
- Word中关于参考文献连续引用
热门文章
- TypeScript方法重载
- OpenStake组件
- 清理win7系统闲置服务器,教你还原win7系统WICleanup清理Windows Installer冗余文件的方案...
- SolidWorks使用教程
- FFmpeg的avcodec_decode_video2()函数
- 对网站服务器日志进行分析
- 《FFmpeg从入门到精通》读书笔记(一)
- c语言 求幂级数展开的部分和
- Twisted核心(官方文档)——3
- 因更新驱动致“win7重启后无法正常启动、无法通过系统还原修复”的解决方案。