github.com/fafucoder/cilium@v1.6.11/proxylib/proxylib_memcached_test.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !privileged_tests 16 17 package main 18 19 import ( 20 "fmt" 21 "testing" 22 23 _ "github.com/cilium/cilium/proxylib/memcached" 24 binarymemcache "github.com/cilium/cilium/proxylib/memcached/binary" 25 textmemcache "github.com/cilium/cilium/proxylib/memcached/text" 26 "github.com/cilium/cilium/proxylib/proxylib" 27 "github.com/cilium/cilium/proxylib/test" 28 29 _ "gopkg.in/check.v1" 30 ) 31 32 var setHelloText = []byte("set key 0 0 5\r\nhello\r\n") 33 var setHelloTextNoreply = []byte("set key 0 0 5 noreply\r\nhello\r\n") 34 35 var getKeysText = []byte("get key1 key2 key3\r\n") 36 var gatKeysText = []byte("gat 5 key1 key2 key3\r\n") 37 var getResponse = []byte( 38 "VALUE key3 0 4\r\n" + 39 "xDDD\r\n" + 40 "VALUE key4 0 3\r\n" + 41 "xDD\r\n" + 42 "END\r\n") 43 44 var deleteText = []byte("delete key\r\n") 45 var incrText = []byte("incr key 5\r\n") 46 var touchText = []byte("touch key 55\r\n") 47 var slabsText = []byte("slabs automove 1\r\n") 48 var okText = []byte("OK\r\n") 49 var lruCrawlerText = []byte("lru_crawler metadump all\r\n") 50 var statsText = []byte("stats\r\n") 51 var flushAllText = []byte("flush_all 15\r\n") 52 var watchText = []byte("watch mutations\r\n") 53 54 var watchReply = []byte( 55 "OK\r\n" + 56 "ts=1538135970.404892 gid=5 type=item_store key=key3 status=stored cmd=set ttl=500 clsid=1\r\n" + 57 "ts=1538135970.404898 gid=6 type=item_store key=key4 status=stored cmd=set ttl=500 clsid=1\r\n" + 58 "ts=1538135974.340708 gid=7 type=item_store key=key3 status=stored cmd=set ttl=500 clsid=1\r\n" + 59 "ts=1538135974.340714 gid=8 type=item_store key=key4 status=stored cmd=set ttl=500 clsid=1\r\n" + 60 "ts=1538135976.436863 gid=9 type=item_store key=key3 status=stored cmd=set ttl=500 clsid=1\r\n") 61 62 var lruCrawlerResponse = []byte( 63 "key=key3 exp=1538047402 la=1538046902 cas=1 fetch=no cls=1 size=67\r\n" + 64 "key=key4 exp=1538047402 la=1538046902 cas=2 fetch=no cls=1 size=66\r\n" + 65 "END\r\n") 66 67 var statsResponse = []byte( 68 "STAT evictions 0\r\n" + 69 "STAT reclaimed 2\r\n" + 70 "STAT crawler_reclaimed\r\n" + 71 "STAT crawler_items_checked 18\r\n" + 72 "STAT lrutail_reflocked 0\r\n" + 73 "STAT moves_to_cold 6\r\n" + 74 "STAT moves_to_warm 0\r\n" + 75 "STAT moves_within_lru 0\r\n" + 76 "STAT direct_reclaims 0\r\n" + 77 "STAT lru_bumps_dropped 0\r\n" + 78 "END\r\n") 79 80 var notFound = []byte("NOT_FOUND\r\n") 81 82 var stored = []byte("STORED\r\n") 83 84 // binary packets 85 var getHello = []byte{ 86 128, 0, 0, 5, 87 0, 0, 0, 0, 88 0, 0, 0, 5, 89 0, 0, 0, 0, 90 0, 0, 0, 0, 91 0, 0, 0, 0, 92 'H', 'e', 'l', 'l', 93 'o', 94 } 95 96 var getHelloResp = []byte{ 97 129, 0, 0, 0, 98 4, 0, 0, 0, 99 0, 0, 0, 9, 100 0, 0, 0, 0, 101 0, 0, 0, 0, 102 0, 0, 0, 0, 103 0, 0, 0, 0, 104 'W', 'o', 'r', 'l', 105 'd', 106 } 107 108 var setHello = []byte{ 109 128, 1, 0, 5, 110 8, 0, 0, 0, 111 0, 0, 0, 18, 112 0, 0, 0, 0, 113 0, 0, 0, 0, 114 0, 0, 0, 0, 115 0, 0, 0, 0, 116 0, 0, 0, 0, 117 'H', 'e', 'l', 'l', 118 'o', 'W', 'o', 'r', 119 'l', 'd', 120 } 121 122 func TestMemcache(t *testing.T) { 123 for _, tc := range append(textTestCases, binaryTestCases...) { 124 t.Run(tc.name, func(t *testing.T) { 125 126 logServer := test.StartAccessLogServer("access_log.sock", 10) 127 defer logServer.Close() 128 129 mod := OpenModule([][2]string{{"access-log-path", logServer.Path}}, false) 130 if mod == 0 { 131 t.Errorf("OpenModule() with access log path %s failed", logServer.Path) 132 } else { 133 defer CloseModule(mod) 134 } 135 136 insertPolicyText(t, mod, "1", []string{fmt.Sprintf(` 137 name: "bm1" 138 policy: 2 139 ingress_per_port_policies: < 140 port: 80 141 rules: < 142 remote_policies: 1 143 remote_policies: 3 144 remote_policies: 4 145 l7_proto: "memcache" 146 l7_rules: < 147 l7_rules: < 148 %s 149 > 150 > 151 > 152 > 153 `, tc.policy)}) 154 155 buf := CheckOnNewConnection(t, mod, "memcache", 1, true, 1, 2, "1.1.1.1:34567", "2.2.2.2:80", "bm1", 156 30, proxylib.OK, 1) 157 158 tc.onDataChecks(t) 159 160 CheckClose(t, 1, buf, 1) 161 }) 162 } 163 } 164 165 type testCase struct { 166 name string 167 policy string 168 onDataChecks func(*testing.T) 169 } 170 171 var textTestCases = []testCase{ 172 { 173 "text set pass", 174 ` rule: < 175 key: "keyExact" 176 value: "" 177 > 178 rule: < 179 key: "command" 180 value: "set" 181 > 182 `, 183 func(t *testing.T) { 184 CheckOnData(t, 1, false, false, &[][]byte{setHelloText}, []ExpFilterOp{ 185 {proxylib.PASS, len(setHelloText)}, {proxylib.MORE, 2}, 186 }, proxylib.OK, "") 187 188 CheckOnData(t, 1, true, false, &[][]byte{stored}, []ExpFilterOp{ 189 {proxylib.PASS, len(stored)}, 190 }, proxylib.OK, "") 191 }, 192 }, 193 { 194 "text set drop", 195 ` rule: < 196 key: "keyExact" 197 value: "trolo" 198 > 199 rule: < 200 key: "command" 201 value: "set" 202 > 203 `, 204 func(t *testing.T) { 205 CheckOnData(t, 1, false, false, &[][]byte{setHelloText}, []ExpFilterOp{ 206 {proxylib.DROP, len(setHelloText)}, {proxylib.MORE, 2}, 207 }, proxylib.OK, string(textmemcache.DeniedMsg)) 208 }, 209 }, 210 { 211 "text get pass", 212 ` rule: < 213 key: "keyExact" 214 value: "" 215 > 216 rule: < 217 key: "command" 218 value: "get" 219 > 220 `, 221 func(t *testing.T) { 222 CheckOnData(t, 1, false, false, &[][]byte{getKeysText, getKeysText}, []ExpFilterOp{ 223 {proxylib.PASS, len(getKeysText)}, {proxylib.PASS, len(getKeysText)}, {proxylib.MORE, 2}, 224 }, proxylib.OK, "") 225 CheckOnData(t, 1, true, false, &[][]byte{getResponse, getResponse}, []ExpFilterOp{ 226 {proxylib.PASS, len(getResponse)}, {proxylib.PASS, len(getResponse)}, 227 }, proxylib.OK, "") 228 }, 229 }, 230 { 231 "text get more", 232 ` rule: < 233 key: "keyExact" 234 value: "" 235 > 236 rule: < 237 key: "command" 238 value: "get" 239 > 240 `, 241 func(t *testing.T) { 242 CheckOnData(t, 1, false, false, &[][]byte{getResponse[:5]}, []ExpFilterOp{ 243 {proxylib.MORE, 2}, 244 }, proxylib.OK, "") 245 }, 246 }, 247 { 248 "text get drop", 249 ` rule: < 250 key: "keyExact" 251 value: "" 252 > 253 rule: < 254 key: "command" 255 value: "set" 256 > 257 `, 258 func(t *testing.T) { 259 CheckOnData(t, 1, false, false, &[][]byte{getKeysText}, []ExpFilterOp{ 260 {proxylib.DROP, len(getKeysText)}, {proxylib.MORE, 2}, 261 }, proxylib.OK, string(textmemcache.DeniedMsg)) 262 }, 263 }, 264 { 265 "text gat pass", 266 ` rule: < 267 key: "keyExact" 268 value: "" 269 > 270 rule: < 271 key: "command" 272 value: "gat" 273 > 274 `, 275 func(t *testing.T) { 276 CheckOnData(t, 1, false, false, &[][]byte{gatKeysText, gatKeysText}, []ExpFilterOp{ 277 {proxylib.PASS, len(gatKeysText)}, {proxylib.PASS, len(gatKeysText)}, {proxylib.MORE, 2}, 278 }, proxylib.OK, "") 279 CheckOnData(t, 1, true, false, &[][]byte{getResponse, getResponse}, []ExpFilterOp{ 280 {proxylib.PASS, len(getResponse)}, {proxylib.PASS, len(getResponse)}, 281 }, proxylib.OK, "") 282 }, 283 }, 284 { 285 "text gat more", 286 ` rule: < 287 key: "keyExact" 288 value: "" 289 > 290 rule: < 291 key: "command" 292 value: "gat" 293 > 294 `, 295 func(t *testing.T) { 296 CheckOnData(t, 1, false, false, &[][]byte{getResponse[:5]}, []ExpFilterOp{ 297 {proxylib.MORE, 2}, 298 }, proxylib.OK, "") 299 }, 300 }, 301 { 302 "text gat drop", 303 ` rule: < 304 key: "keyExact" 305 value: "" 306 > 307 rule: < 308 key: "command" 309 value: "set" 310 > 311 `, 312 func(t *testing.T) { 313 CheckOnData(t, 1, false, false, &[][]byte{gatKeysText}, []ExpFilterOp{ 314 {proxylib.DROP, len(gatKeysText)}, {proxylib.MORE, 2}, 315 }, proxylib.OK, string(textmemcache.DeniedMsg)) 316 }, 317 }, 318 { 319 "text delete pass", 320 ` rule: < 321 key: "keyExact" 322 value: "" 323 > 324 rule: < 325 key: "command" 326 value: "delete" 327 > 328 `, 329 func(t *testing.T) { 330 331 CheckOnData(t, 1, false, false, &[][]byte{deleteText}, []ExpFilterOp{ 332 {proxylib.PASS, len(deleteText)}, {proxylib.MORE, 2}, 333 }, proxylib.OK, "") 334 335 CheckOnData(t, 1, true, false, &[][]byte{notFound}, []ExpFilterOp{ 336 {proxylib.PASS, len(notFound)}, 337 }, proxylib.OK, "") 338 }, 339 }, 340 { 341 "text delete drop", 342 ` rule: < 343 key: "keyExact" 344 value: "" 345 > 346 rule: < 347 key: "command" 348 value: "set" 349 > 350 `, 351 func(t *testing.T) { 352 CheckOnData(t, 1, false, false, &[][]byte{deleteText}, []ExpFilterOp{ 353 {proxylib.DROP, len(deleteText)}, {proxylib.MORE, 2}, 354 }, proxylib.OK, string(textmemcache.DeniedMsg)) 355 }, 356 }, 357 { 358 "text incr pass", 359 ` rule: < 360 key: "keyExact" 361 value: "" 362 > 363 rule: < 364 key: "command" 365 value: "incr" 366 > 367 `, 368 func(t *testing.T) { 369 370 CheckOnData(t, 1, false, false, &[][]byte{incrText}, []ExpFilterOp{ 371 {proxylib.PASS, len(incrText)}, {proxylib.MORE, 2}, 372 }, proxylib.OK, "") 373 374 CheckOnData(t, 1, true, false, &[][]byte{notFound}, []ExpFilterOp{ 375 {proxylib.PASS, len(notFound)}, 376 }, proxylib.OK, "") 377 }, 378 }, 379 { 380 "text incr drop", 381 ` rule: < 382 key: "keyExact" 383 value: "otherKey" 384 > 385 rule: < 386 key: "command" 387 value: "incr" 388 > 389 `, 390 func(t *testing.T) { 391 CheckOnData(t, 1, false, false, &[][]byte{incrText}, []ExpFilterOp{ 392 {proxylib.DROP, len(incrText)}, {proxylib.MORE, 2}, 393 }, proxylib.OK, string(textmemcache.DeniedMsg)) 394 }, 395 }, 396 { 397 "text touch pass", 398 ` rule: < 399 key: "keyExact" 400 value: "key" 401 > 402 rule: < 403 key: "command" 404 value: "touch" 405 > 406 `, 407 func(t *testing.T) { 408 409 CheckOnData(t, 1, false, false, &[][]byte{touchText}, []ExpFilterOp{ 410 {proxylib.PASS, len(touchText)}, {proxylib.MORE, 2}, 411 }, proxylib.OK, "") 412 413 CheckOnData(t, 1, true, false, &[][]byte{notFound}, []ExpFilterOp{ 414 {proxylib.PASS, len(notFound)}, 415 }, proxylib.OK, "") 416 }, 417 }, 418 { 419 "text touch drop", 420 ` rule: < 421 key: "keyExact" 422 value: "otherKey" 423 > 424 rule: < 425 key: "command" 426 value: "touch" 427 > 428 `, 429 func(t *testing.T) { 430 CheckOnData(t, 1, false, false, &[][]byte{touchText}, []ExpFilterOp{ 431 {proxylib.DROP, len(touchText)}, {proxylib.MORE, 2}, 432 }, proxylib.OK, string(textmemcache.DeniedMsg)) 433 }, 434 }, 435 { 436 "text slabs pass", 437 ` rule: < 438 key: "command" 439 value: "slabs" 440 > 441 `, 442 func(t *testing.T) { 443 444 CheckOnData(t, 1, false, false, &[][]byte{slabsText}, []ExpFilterOp{ 445 {proxylib.PASS, len(slabsText)}, {proxylib.MORE, 2}, 446 }, proxylib.OK, "") 447 448 CheckOnData(t, 1, true, false, &[][]byte{okText}, []ExpFilterOp{ 449 {proxylib.PASS, len(okText)}, 450 }, proxylib.OK, "") 451 }, 452 }, 453 { 454 "text slabs drop", 455 ` rule: < 456 key: "keyExact" 457 value: "otherKey" 458 > 459 rule: < 460 key: "command" 461 value: "touch" 462 > 463 `, 464 func(t *testing.T) { 465 CheckOnData(t, 1, false, false, &[][]byte{slabsText}, []ExpFilterOp{ 466 {proxylib.DROP, len(slabsText)}, {proxylib.MORE, 2}, 467 }, proxylib.OK, string(textmemcache.DeniedMsg)) 468 }, 469 }, 470 { 471 "text lru_crawler response req more and pass", 472 ` rule: < 473 key: "command" 474 value: "lru_crawler" 475 > 476 `, 477 func(t *testing.T) { 478 CheckOnData(t, 1, false, false, &[][]byte{lruCrawlerText}, []ExpFilterOp{ 479 {proxylib.PASS, len(lruCrawlerText)}, {proxylib.MORE, 2}, 480 }, proxylib.OK, "") 481 482 CheckOnData(t, 1, true, false, &[][]byte{lruCrawlerResponse[:5]}, []ExpFilterOp{ 483 {proxylib.MORE, 2}, 484 }, proxylib.OK, "") 485 CheckOnData(t, 1, true, false, &[][]byte{lruCrawlerResponse}, []ExpFilterOp{ 486 {proxylib.PASS, len(lruCrawlerResponse)}, 487 }, proxylib.OK, "") 488 }, 489 }, 490 { 491 "text stats response req more and pass", 492 ` rule: < 493 key: "command" 494 value: "stats" 495 > 496 `, 497 func(t *testing.T) { 498 499 CheckOnData(t, 1, false, false, &[][]byte{statsText}, []ExpFilterOp{ 500 {proxylib.PASS, len(statsText)}, {proxylib.MORE, 2}, 501 }, proxylib.OK, "") 502 503 CheckOnData(t, 1, true, false, &[][]byte{statsResponse[:5]}, []ExpFilterOp{ 504 {proxylib.MORE, 2}, 505 }, proxylib.OK, "") 506 CheckOnData(t, 1, true, false, &[][]byte{statsResponse}, []ExpFilterOp{ 507 {proxylib.PASS, len(statsResponse)}, 508 }, proxylib.OK, "") 509 }, 510 }, 511 { 512 "text flush_all pass", 513 ` rule: < 514 key: "command" 515 value: "flush_all" 516 > 517 `, 518 func(t *testing.T) { 519 520 CheckOnData(t, 1, false, false, &[][]byte{flushAllText}, []ExpFilterOp{ 521 {proxylib.PASS, len(flushAllText)}, {proxylib.MORE, 2}, 522 }, proxylib.OK, "") 523 524 }, 525 }, 526 { 527 "text flush_all denied", 528 ` rule: < 529 key: "command" 530 value: "get" 531 > 532 `, 533 func(t *testing.T) { 534 535 CheckOnData(t, 1, false, false, &[][]byte{flushAllText}, []ExpFilterOp{ 536 {proxylib.DROP, len(flushAllText)}, {proxylib.MORE, 2}, 537 }, proxylib.OK, string(textmemcache.DeniedMsg)) 538 539 }, 540 }, 541 { 542 "text watch passed", 543 ` rule: < 544 key: "command" 545 value: "watch" 546 > 547 `, 548 func(t *testing.T) { 549 550 CheckOnData(t, 1, false, false, &[][]byte{watchText}, []ExpFilterOp{ 551 {proxylib.PASS, len(watchText)}, {proxylib.MORE, 2}, 552 }, proxylib.OK, "") 553 554 CheckOnData(t, 1, true, false, &[][]byte{watchReply}, []ExpFilterOp{ 555 {proxylib.PASS, 4}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, 556 }, proxylib.OK, "") 557 }, 558 }, 559 { 560 "text partial linefeed", 561 ` rule: < 562 key: "keyExact" 563 value: "" 564 > 565 rule: < 566 key: "command" 567 value: "set" 568 > 569 `, 570 func(t *testing.T) { 571 572 CheckOnData(t, 1, false, false, &[][]byte{getKeysText[:len(getKeysText)-1]}, []ExpFilterOp{ 573 {proxylib.MORE, 1}, 574 }, proxylib.OK, "") 575 }, 576 }, 577 { 578 "text set pass on empty rule", 579 "", 580 func(t *testing.T) { 581 CheckOnData(t, 1, false, false, &[][]byte{setHelloText}, []ExpFilterOp{ 582 {proxylib.PASS, len(setHelloText)}, {proxylib.MORE, 2}, 583 }, proxylib.OK, "") 584 585 CheckOnData(t, 1, true, false, &[][]byte{stored}, []ExpFilterOp{ 586 {proxylib.PASS, len(stored)}, 587 }, proxylib.OK, "") 588 }, 589 }, 590 } 591 592 var binaryTestCases = []testCase{ 593 { 594 "bin get pass exact key", 595 ` rule: < 596 key: "keyExact" 597 value: "Hello" 598 > 599 rule: < 600 key: "command" 601 value: "get" 602 > 603 `, 604 func(t *testing.T) { 605 CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{ 606 {proxylib.PASS, len(getHello)}, {proxylib.MORE, 24}, 607 }, proxylib.OK, "") 608 }, 609 }, 610 { 611 "bin get pass prefix key", 612 ` rule: < 613 key: "keyPrefix" 614 value: "Hell" 615 > 616 rule: < 617 key: "command" 618 value: "get" 619 > 620 `, 621 func(t *testing.T) { 622 CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{ 623 {proxylib.PASS, len(getHello)}, {proxylib.MORE, 24}, 624 }, proxylib.OK, "") 625 }, 626 }, 627 { 628 "bin get pass regex key", 629 ` rule: < 630 key: "keyRegex" 631 value: "^.el.o$" 632 > 633 rule: < 634 key: "command" 635 value: "get" 636 > 637 `, 638 func(t *testing.T) { 639 CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{ 640 {proxylib.PASS, len(getHello)}, {proxylib.MORE, 24}, 641 }, proxylib.OK, "") 642 }, 643 }, 644 { 645 "bin get drop", 646 ` rule: < 647 key: "keyExact" 648 value: "" 649 > 650 rule: < 651 key: "command" 652 value: "set" 653 > 654 `, 655 func(t *testing.T) { 656 CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{ 657 {proxylib.DROP, len(getHello)}, {proxylib.MORE, 24}, 658 }, proxylib.OK, string(binarymemcache.DeniedMsgBase)) 659 }, 660 }, 661 { 662 "bin get more", 663 ` rule: < 664 key: "keyExact" 665 value: "" 666 > 667 rule: < 668 key: "command" 669 value: "get" 670 > 671 `, 672 func(t *testing.T) { 673 data := getHello[:10] 674 CheckOnData(t, 1, false, false, &[][]byte{data}, []ExpFilterOp{{proxylib.MORE, 14}}, proxylib.OK, "") 675 }, 676 }, 677 { 678 "bin get split", 679 ` rule: < 680 key: "keyExact" 681 value: "" 682 > 683 rule: < 684 key: "command" 685 value: "get" 686 > 687 `, 688 func(t *testing.T) { 689 data := getHello 690 CheckOnData(t, 1, false, false, &[][]byte{data[:10], data[10:]}, []ExpFilterOp{ 691 {proxylib.PASS, len(data)}, {proxylib.MORE, 24}, 692 }, proxylib.OK, "") 693 }, 694 }, 695 { 696 "bin get remaining key", 697 ` rule: < 698 key: "keyExact" 699 value: "" 700 > 701 rule: < 702 key: "command" 703 value: "get" 704 > 705 `, 706 func(t *testing.T) { 707 data := getHello[:26] 708 CheckOnData(t, 1, false, false, &[][]byte{data}, []ExpFilterOp{ 709 {proxylib.MORE, 3}, 710 }, proxylib.OK, "") 711 }, 712 }, 713 { 714 "bin set drop and allow", 715 ` rule: < 716 key: "keyExact" 717 value: "" 718 > 719 rule: < 720 key: "command" 721 value: "set" 722 > 723 `, 724 func(t *testing.T) { 725 CheckOnData(t, 1, false, false, &[][]byte{setHello, getHello}, []ExpFilterOp{ 726 {proxylib.PASS, len(setHello)}, {proxylib.DROP, len(getHello)}, {proxylib.MORE, 24}, 727 }, proxylib.OK, string(binarymemcache.DeniedMsgBase)) 728 729 CheckOnData(t, 1, true, false, &[][]byte{getHelloResp}, []ExpFilterOp{ 730 {proxylib.PASS, len(getHelloResp)}, {proxylib.INJECT, len(binarymemcache.DeniedMsgBase)}, 731 }, proxylib.OK, string(binarymemcache.DeniedMsgBase)) 732 }, 733 }, 734 }